138fd1498Szrj /* Driver of optimization process
238fd1498Szrj Copyright (C) 2003-2018 Free Software Foundation, Inc.
338fd1498Szrj Contributed by Jan Hubicka
438fd1498Szrj
538fd1498Szrj This file is part of GCC.
638fd1498Szrj
738fd1498Szrj GCC is free software; you can redistribute it and/or modify it under
838fd1498Szrj the terms of the GNU General Public License as published by the Free
938fd1498Szrj Software Foundation; either version 3, or (at your option) any later
1038fd1498Szrj version.
1138fd1498Szrj
1238fd1498Szrj GCC is distributed in the hope that it will be useful, but WITHOUT ANY
1338fd1498Szrj WARRANTY; without even the implied warranty of MERCHANTABILITY or
1438fd1498Szrj FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
1538fd1498Szrj for more details.
1638fd1498Szrj
1738fd1498Szrj You should have received a copy of the GNU General Public License
1838fd1498Szrj along with GCC; see the file COPYING3. If not see
1938fd1498Szrj <http://www.gnu.org/licenses/>. */
2038fd1498Szrj
2138fd1498Szrj /* This module implements main driver of compilation process.
2238fd1498Szrj
2338fd1498Szrj The main scope of this file is to act as an interface in between
2438fd1498Szrj tree based frontends and the backend.
2538fd1498Szrj
2638fd1498Szrj The front-end is supposed to use following functionality:
2738fd1498Szrj
2838fd1498Szrj - finalize_function
2938fd1498Szrj
3038fd1498Szrj This function is called once front-end has parsed whole body of function
3138fd1498Szrj and it is certain that the function body nor the declaration will change.
3238fd1498Szrj
3338fd1498Szrj (There is one exception needed for implementing GCC extern inline
3438fd1498Szrj function.)
3538fd1498Szrj
3638fd1498Szrj - varpool_finalize_decl
3738fd1498Szrj
3838fd1498Szrj This function has same behavior as the above but is used for static
3938fd1498Szrj variables.
4038fd1498Szrj
4138fd1498Szrj - add_asm_node
4238fd1498Szrj
4338fd1498Szrj Insert new toplevel ASM statement
4438fd1498Szrj
4538fd1498Szrj - finalize_compilation_unit
4638fd1498Szrj
4738fd1498Szrj This function is called once (source level) compilation unit is finalized
4838fd1498Szrj and it will no longer change.
4938fd1498Szrj
5038fd1498Szrj The symbol table is constructed starting from the trivially needed
5138fd1498Szrj symbols finalized by the frontend. Functions are lowered into
5238fd1498Szrj GIMPLE representation and callgraph/reference lists are constructed.
5338fd1498Szrj Those are used to discover other necessary functions and variables.
5438fd1498Szrj
5538fd1498Szrj At the end the bodies of unreachable functions are removed.
5638fd1498Szrj
5738fd1498Szrj The function can be called multiple times when multiple source level
5838fd1498Szrj compilation units are combined.
5938fd1498Szrj
6038fd1498Szrj - compile
6138fd1498Szrj
6238fd1498Szrj This passes control to the back-end. Optimizations are performed and
6338fd1498Szrj final assembler is generated. This is done in the following way. Note
6438fd1498Szrj that with link time optimization the process is split into three
6538fd1498Szrj stages (compile time, linktime analysis and parallel linktime as
6638fd1498Szrj indicated bellow).
6738fd1498Szrj
6838fd1498Szrj Compile time:
6938fd1498Szrj
7038fd1498Szrj 1) Inter-procedural optimization.
7138fd1498Szrj (ipa_passes)
7238fd1498Szrj
7338fd1498Szrj This part is further split into:
7438fd1498Szrj
7538fd1498Szrj a) early optimizations. These are local passes executed in
7638fd1498Szrj the topological order on the callgraph.
7738fd1498Szrj
7838fd1498Szrj The purpose of early optimiations is to optimize away simple
7938fd1498Szrj things that may otherwise confuse IP analysis. Very simple
8038fd1498Szrj propagation across the callgraph is done i.e. to discover
8138fd1498Szrj functions without side effects and simple inlining is performed.
8238fd1498Szrj
8338fd1498Szrj b) early small interprocedural passes.
8438fd1498Szrj
8538fd1498Szrj Those are interprocedural passes executed only at compilation
8638fd1498Szrj time. These include, for example, transational memory lowering,
8738fd1498Szrj unreachable code removal and other simple transformations.
8838fd1498Szrj
8938fd1498Szrj c) IP analysis stage. All interprocedural passes do their
9038fd1498Szrj analysis.
9138fd1498Szrj
9238fd1498Szrj Interprocedural passes differ from small interprocedural
9338fd1498Szrj passes by their ability to operate across whole program
9438fd1498Szrj at linktime. Their analysis stage is performed early to
9538fd1498Szrj both reduce linking times and linktime memory usage by
9638fd1498Szrj not having to represent whole program in memory.
9738fd1498Szrj
9838fd1498Szrj d) LTO sreaming. When doing LTO, everything important gets
9938fd1498Szrj streamed into the object file.
10038fd1498Szrj
10138fd1498Szrj Compile time and or linktime analysis stage (WPA):
10238fd1498Szrj
10338fd1498Szrj At linktime units gets streamed back and symbol table is
10438fd1498Szrj merged. Function bodies are not streamed in and not
10538fd1498Szrj available.
10638fd1498Szrj e) IP propagation stage. All IP passes execute their
10738fd1498Szrj IP propagation. This is done based on the earlier analysis
10838fd1498Szrj without having function bodies at hand.
10938fd1498Szrj f) Ltrans streaming. When doing WHOPR LTO, the program
11038fd1498Szrj is partitioned and streamed into multple object files.
11138fd1498Szrj
11238fd1498Szrj Compile time and/or parallel linktime stage (ltrans)
11338fd1498Szrj
11438fd1498Szrj Each of the object files is streamed back and compiled
11538fd1498Szrj separately. Now the function bodies becomes available
11638fd1498Szrj again.
11738fd1498Szrj
11838fd1498Szrj 2) Virtual clone materialization
11938fd1498Szrj (cgraph_materialize_clone)
12038fd1498Szrj
12138fd1498Szrj IP passes can produce copies of existing functoins (such
12238fd1498Szrj as versioned clones or inline clones) without actually
12338fd1498Szrj manipulating their bodies by creating virtual clones in
12438fd1498Szrj the callgraph. At this time the virtual clones are
12538fd1498Szrj turned into real functions
12638fd1498Szrj 3) IP transformation
12738fd1498Szrj
12838fd1498Szrj All IP passes transform function bodies based on earlier
12938fd1498Szrj decision of the IP propagation.
13038fd1498Szrj
13138fd1498Szrj 4) late small IP passes
13238fd1498Szrj
13338fd1498Szrj Simple IP passes working within single program partition.
13438fd1498Szrj
13538fd1498Szrj 5) Expansion
13638fd1498Szrj (expand_all_functions)
13738fd1498Szrj
13838fd1498Szrj At this stage functions that needs to be output into
13938fd1498Szrj assembler are identified and compiled in topological order
14038fd1498Szrj 6) Output of variables and aliases
14138fd1498Szrj Now it is known what variable references was not optimized
14238fd1498Szrj out and thus all variables are output to the file.
14338fd1498Szrj
14438fd1498Szrj Note that with -fno-toplevel-reorder passes 5 and 6
14538fd1498Szrj are combined together in cgraph_output_in_order.
14638fd1498Szrj
14738fd1498Szrj Finally there are functions to manipulate the callgraph from
14838fd1498Szrj backend.
14938fd1498Szrj - cgraph_add_new_function is used to add backend produced
15038fd1498Szrj functions introduced after the unit is finalized.
15138fd1498Szrj The functions are enqueue for later processing and inserted
15238fd1498Szrj into callgraph with cgraph_process_new_functions.
15338fd1498Szrj
15438fd1498Szrj - cgraph_function_versioning
15538fd1498Szrj
15638fd1498Szrj produces a copy of function into new one (a version)
15738fd1498Szrj and apply simple transformations
15838fd1498Szrj */
15938fd1498Szrj
16038fd1498Szrj #include "config.h"
16138fd1498Szrj #include "system.h"
16238fd1498Szrj #include "coretypes.h"
16338fd1498Szrj #include "backend.h"
16438fd1498Szrj #include "target.h"
16538fd1498Szrj #include "rtl.h"
16638fd1498Szrj #include "tree.h"
16738fd1498Szrj #include "gimple.h"
16838fd1498Szrj #include "cfghooks.h"
16938fd1498Szrj #include "regset.h" /* FIXME: For reg_obstack. */
17038fd1498Szrj #include "alloc-pool.h"
17138fd1498Szrj #include "tree-pass.h"
17238fd1498Szrj #include "stringpool.h"
17338fd1498Szrj #include "gimple-ssa.h"
17438fd1498Szrj #include "cgraph.h"
17538fd1498Szrj #include "coverage.h"
17638fd1498Szrj #include "lto-streamer.h"
17738fd1498Szrj #include "fold-const.h"
17838fd1498Szrj #include "varasm.h"
17938fd1498Szrj #include "stor-layout.h"
18038fd1498Szrj #include "output.h"
18138fd1498Szrj #include "cfgcleanup.h"
18238fd1498Szrj #include "gimple-fold.h"
18338fd1498Szrj #include "gimplify.h"
18438fd1498Szrj #include "gimple-iterator.h"
18538fd1498Szrj #include "gimplify-me.h"
18638fd1498Szrj #include "tree-cfg.h"
18738fd1498Szrj #include "tree-into-ssa.h"
18838fd1498Szrj #include "tree-ssa.h"
18938fd1498Szrj #include "langhooks.h"
19038fd1498Szrj #include "toplev.h"
19138fd1498Szrj #include "debug.h"
19238fd1498Szrj #include "symbol-summary.h"
19338fd1498Szrj #include "tree-vrp.h"
19438fd1498Szrj #include "ipa-prop.h"
19538fd1498Szrj #include "gimple-pretty-print.h"
19638fd1498Szrj #include "plugin.h"
19738fd1498Szrj #include "ipa-fnsummary.h"
19838fd1498Szrj #include "ipa-utils.h"
19938fd1498Szrj #include "except.h"
20038fd1498Szrj #include "cfgloop.h"
20138fd1498Szrj #include "context.h"
20238fd1498Szrj #include "pass_manager.h"
20338fd1498Szrj #include "tree-nested.h"
20438fd1498Szrj #include "dbgcnt.h"
20538fd1498Szrj #include "tree-chkp.h"
20638fd1498Szrj #include "lto-section-names.h"
20738fd1498Szrj #include "stringpool.h"
20838fd1498Szrj #include "attribs.h"
20938fd1498Szrj
21038fd1498Szrj /* Queue of cgraph nodes scheduled to be added into cgraph. This is a
21138fd1498Szrj secondary queue used during optimization to accommodate passes that
21238fd1498Szrj may generate new functions that need to be optimized and expanded. */
21338fd1498Szrj vec<cgraph_node *> cgraph_new_nodes;
21438fd1498Szrj
21538fd1498Szrj static void expand_all_functions (void);
21638fd1498Szrj static void mark_functions_to_output (void);
21738fd1498Szrj static void handle_alias_pairs (void);
21838fd1498Szrj
21938fd1498Szrj /* Used for vtable lookup in thunk adjusting. */
22038fd1498Szrj static GTY (()) tree vtable_entry_type;
22138fd1498Szrj
22238fd1498Szrj /* Return true if this symbol is a function from the C frontend specified
22338fd1498Szrj directly in RTL form (with "__RTL"). */
22438fd1498Szrj
22538fd1498Szrj bool
native_rtl_p()22638fd1498Szrj symtab_node::native_rtl_p () const
22738fd1498Szrj {
22838fd1498Szrj if (TREE_CODE (decl) != FUNCTION_DECL)
22938fd1498Szrj return false;
23038fd1498Szrj if (!DECL_STRUCT_FUNCTION (decl))
23138fd1498Szrj return false;
23238fd1498Szrj return DECL_STRUCT_FUNCTION (decl)->curr_properties & PROP_rtl;
23338fd1498Szrj }
23438fd1498Szrj
23538fd1498Szrj /* Determine if symbol declaration is needed. That is, visible to something
23638fd1498Szrj either outside this translation unit, something magic in the system
23738fd1498Szrj configury */
23838fd1498Szrj bool
needed_p(void)23938fd1498Szrj symtab_node::needed_p (void)
24038fd1498Szrj {
24138fd1498Szrj /* Double check that no one output the function into assembly file
24238fd1498Szrj early. */
24338fd1498Szrj if (!native_rtl_p ())
24438fd1498Szrj gcc_checking_assert
24538fd1498Szrj (!DECL_ASSEMBLER_NAME_SET_P (decl)
24638fd1498Szrj || !TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl)));
24738fd1498Szrj
24838fd1498Szrj if (!definition)
24938fd1498Szrj return false;
25038fd1498Szrj
25138fd1498Szrj if (DECL_EXTERNAL (decl))
25238fd1498Szrj return false;
25338fd1498Szrj
25438fd1498Szrj /* If the user told us it is used, then it must be so. */
25538fd1498Szrj if (force_output)
25638fd1498Szrj return true;
25738fd1498Szrj
25838fd1498Szrj /* ABI forced symbols are needed when they are external. */
25938fd1498Szrj if (forced_by_abi && TREE_PUBLIC (decl))
26038fd1498Szrj return true;
26138fd1498Szrj
26238fd1498Szrj /* Keep constructors, destructors and virtual functions. */
26338fd1498Szrj if (TREE_CODE (decl) == FUNCTION_DECL
26438fd1498Szrj && (DECL_STATIC_CONSTRUCTOR (decl) || DECL_STATIC_DESTRUCTOR (decl)))
26538fd1498Szrj return true;
26638fd1498Szrj
26738fd1498Szrj /* Externally visible variables must be output. The exception is
26838fd1498Szrj COMDAT variables that must be output only when they are needed. */
26938fd1498Szrj if (TREE_PUBLIC (decl) && !DECL_COMDAT (decl))
27038fd1498Szrj return true;
27138fd1498Szrj
27238fd1498Szrj return false;
27338fd1498Szrj }
27438fd1498Szrj
27538fd1498Szrj /* Head and terminator of the queue of nodes to be processed while building
27638fd1498Szrj callgraph. */
27738fd1498Szrj
27838fd1498Szrj static symtab_node symtab_terminator;
27938fd1498Szrj static symtab_node *queued_nodes = &symtab_terminator;
28038fd1498Szrj
28138fd1498Szrj /* Add NODE to queue starting at QUEUED_NODES.
28238fd1498Szrj The queue is linked via AUX pointers and terminated by pointer to 1. */
28338fd1498Szrj
28438fd1498Szrj static void
enqueue_node(symtab_node * node)28538fd1498Szrj enqueue_node (symtab_node *node)
28638fd1498Szrj {
28738fd1498Szrj if (node->aux)
28838fd1498Szrj return;
28938fd1498Szrj gcc_checking_assert (queued_nodes);
29038fd1498Szrj node->aux = queued_nodes;
29138fd1498Szrj queued_nodes = node;
29238fd1498Szrj }
29338fd1498Szrj
29438fd1498Szrj /* Process CGRAPH_NEW_FUNCTIONS and perform actions necessary to add these
29538fd1498Szrj functions into callgraph in a way so they look like ordinary reachable
29638fd1498Szrj functions inserted into callgraph already at construction time. */
29738fd1498Szrj
29838fd1498Szrj void
process_new_functions(void)29938fd1498Szrj symbol_table::process_new_functions (void)
30038fd1498Szrj {
30138fd1498Szrj tree fndecl;
30238fd1498Szrj
30338fd1498Szrj if (!cgraph_new_nodes.exists ())
30438fd1498Szrj return;
30538fd1498Szrj
30638fd1498Szrj handle_alias_pairs ();
30738fd1498Szrj /* Note that this queue may grow as its being processed, as the new
30838fd1498Szrj functions may generate new ones. */
30938fd1498Szrj for (unsigned i = 0; i < cgraph_new_nodes.length (); i++)
31038fd1498Szrj {
31138fd1498Szrj cgraph_node *node = cgraph_new_nodes[i];
31238fd1498Szrj fndecl = node->decl;
31338fd1498Szrj switch (state)
31438fd1498Szrj {
31538fd1498Szrj case CONSTRUCTION:
31638fd1498Szrj /* At construction time we just need to finalize function and move
31738fd1498Szrj it into reachable functions list. */
31838fd1498Szrj
31938fd1498Szrj cgraph_node::finalize_function (fndecl, false);
32038fd1498Szrj call_cgraph_insertion_hooks (node);
32138fd1498Szrj enqueue_node (node);
32238fd1498Szrj break;
32338fd1498Szrj
32438fd1498Szrj case IPA:
32538fd1498Szrj case IPA_SSA:
32638fd1498Szrj case IPA_SSA_AFTER_INLINING:
32738fd1498Szrj /* When IPA optimization already started, do all essential
32838fd1498Szrj transformations that has been already performed on the whole
32938fd1498Szrj cgraph but not on this function. */
33038fd1498Szrj
33138fd1498Szrj gimple_register_cfg_hooks ();
33238fd1498Szrj if (!node->analyzed)
33338fd1498Szrj node->analyze ();
33438fd1498Szrj push_cfun (DECL_STRUCT_FUNCTION (fndecl));
33538fd1498Szrj if ((state == IPA_SSA || state == IPA_SSA_AFTER_INLINING)
33638fd1498Szrj && !gimple_in_ssa_p (DECL_STRUCT_FUNCTION (fndecl)))
33738fd1498Szrj {
33838fd1498Szrj bool summaried_computed = ipa_fn_summaries != NULL;
33938fd1498Szrj g->get_passes ()->execute_early_local_passes ();
34038fd1498Szrj /* Early passes compure inline parameters to do inlining
34138fd1498Szrj and splitting. This is redundant for functions added late.
34238fd1498Szrj Just throw away whatever it did. */
34338fd1498Szrj if (!summaried_computed)
34438fd1498Szrj ipa_free_fn_summary ();
34538fd1498Szrj }
34638fd1498Szrj else if (ipa_fn_summaries != NULL)
34738fd1498Szrj compute_fn_summary (node, true);
34838fd1498Szrj free_dominance_info (CDI_POST_DOMINATORS);
34938fd1498Szrj free_dominance_info (CDI_DOMINATORS);
35038fd1498Szrj pop_cfun ();
35138fd1498Szrj call_cgraph_insertion_hooks (node);
35238fd1498Szrj break;
35338fd1498Szrj
35438fd1498Szrj case EXPANSION:
35538fd1498Szrj /* Functions created during expansion shall be compiled
35638fd1498Szrj directly. */
35738fd1498Szrj node->process = 0;
35838fd1498Szrj call_cgraph_insertion_hooks (node);
35938fd1498Szrj node->expand ();
36038fd1498Szrj break;
36138fd1498Szrj
36238fd1498Szrj default:
36338fd1498Szrj gcc_unreachable ();
36438fd1498Szrj break;
36538fd1498Szrj }
36638fd1498Szrj }
36738fd1498Szrj
36838fd1498Szrj cgraph_new_nodes.release ();
36938fd1498Szrj }
37038fd1498Szrj
37138fd1498Szrj /* As an GCC extension we allow redefinition of the function. The
37238fd1498Szrj semantics when both copies of bodies differ is not well defined.
37338fd1498Szrj We replace the old body with new body so in unit at a time mode
37438fd1498Szrj we always use new body, while in normal mode we may end up with
37538fd1498Szrj old body inlined into some functions and new body expanded and
37638fd1498Szrj inlined in others.
37738fd1498Szrj
37838fd1498Szrj ??? It may make more sense to use one body for inlining and other
37938fd1498Szrj body for expanding the function but this is difficult to do. */
38038fd1498Szrj
38138fd1498Szrj void
reset(void)38238fd1498Szrj cgraph_node::reset (void)
38338fd1498Szrj {
38438fd1498Szrj /* If process is set, then we have already begun whole-unit analysis.
38538fd1498Szrj This is *not* testing for whether we've already emitted the function.
38638fd1498Szrj That case can be sort-of legitimately seen with real function redefinition
38738fd1498Szrj errors. I would argue that the front end should never present us with
38838fd1498Szrj such a case, but don't enforce that for now. */
38938fd1498Szrj gcc_assert (!process);
39038fd1498Szrj
39138fd1498Szrj /* Reset our data structures so we can analyze the function again. */
39238fd1498Szrj memset (&local, 0, sizeof (local));
39338fd1498Szrj memset (&global, 0, sizeof (global));
39438fd1498Szrj memset (&rtl, 0, sizeof (rtl));
39538fd1498Szrj analyzed = false;
39638fd1498Szrj definition = false;
39738fd1498Szrj alias = false;
39838fd1498Szrj transparent_alias = false;
39938fd1498Szrj weakref = false;
40038fd1498Szrj cpp_implicit_alias = false;
40138fd1498Szrj
40238fd1498Szrj remove_callees ();
40338fd1498Szrj remove_all_references ();
40438fd1498Szrj }
40538fd1498Szrj
40638fd1498Szrj /* Return true when there are references to the node. INCLUDE_SELF is
40738fd1498Szrj true if a self reference counts as a reference. */
40838fd1498Szrj
40938fd1498Szrj bool
referred_to_p(bool include_self)41038fd1498Szrj symtab_node::referred_to_p (bool include_self)
41138fd1498Szrj {
41238fd1498Szrj ipa_ref *ref = NULL;
41338fd1498Szrj
41438fd1498Szrj /* See if there are any references at all. */
41538fd1498Szrj if (iterate_referring (0, ref))
41638fd1498Szrj return true;
41738fd1498Szrj /* For functions check also calls. */
41838fd1498Szrj cgraph_node *cn = dyn_cast <cgraph_node *> (this);
41938fd1498Szrj if (cn && cn->callers)
42038fd1498Szrj {
42138fd1498Szrj if (include_self)
42238fd1498Szrj return true;
42338fd1498Szrj for (cgraph_edge *e = cn->callers; e; e = e->next_caller)
42438fd1498Szrj if (e->caller != this)
42538fd1498Szrj return true;
42638fd1498Szrj }
42738fd1498Szrj return false;
42838fd1498Szrj }
42938fd1498Szrj
43038fd1498Szrj /* DECL has been parsed. Take it, queue it, compile it at the whim of the
43138fd1498Szrj logic in effect. If NO_COLLECT is true, then our caller cannot stand to have
43238fd1498Szrj the garbage collector run at the moment. We would need to either create
43338fd1498Szrj a new GC context, or just not compile right now. */
43438fd1498Szrj
43538fd1498Szrj void
finalize_function(tree decl,bool no_collect)43638fd1498Szrj cgraph_node::finalize_function (tree decl, bool no_collect)
43738fd1498Szrj {
43838fd1498Szrj cgraph_node *node = cgraph_node::get_create (decl);
43938fd1498Szrj
44038fd1498Szrj if (node->definition)
44138fd1498Szrj {
44238fd1498Szrj /* Nested functions should only be defined once. */
44338fd1498Szrj gcc_assert (!DECL_CONTEXT (decl)
44438fd1498Szrj || TREE_CODE (DECL_CONTEXT (decl)) != FUNCTION_DECL);
44538fd1498Szrj node->reset ();
44638fd1498Szrj node->local.redefined_extern_inline = true;
44738fd1498Szrj }
44838fd1498Szrj
44938fd1498Szrj /* Set definition first before calling notice_global_symbol so that
45038fd1498Szrj it is available to notice_global_symbol. */
45138fd1498Szrj node->definition = true;
45238fd1498Szrj notice_global_symbol (decl);
45338fd1498Szrj node->lowered = DECL_STRUCT_FUNCTION (decl)->cfg != NULL;
45438fd1498Szrj if (!flag_toplevel_reorder)
45538fd1498Szrj node->no_reorder = true;
45638fd1498Szrj
45738fd1498Szrj /* With -fkeep-inline-functions we are keeping all inline functions except
45838fd1498Szrj for extern inline ones. */
45938fd1498Szrj if (flag_keep_inline_functions
46038fd1498Szrj && DECL_DECLARED_INLINE_P (decl)
46138fd1498Szrj && !DECL_EXTERNAL (decl)
46238fd1498Szrj && !DECL_DISREGARD_INLINE_LIMITS (decl))
46338fd1498Szrj node->force_output = 1;
46438fd1498Szrj
46538fd1498Szrj /* __RTL functions were already output as soon as they were parsed (due
46638fd1498Szrj to the large amount of global state in the backend).
46738fd1498Szrj Mark such functions as "force_output" to reflect the fact that they
46838fd1498Szrj will be in the asm file when considering the symbols they reference.
46938fd1498Szrj The attempt to output them later on will bail out immediately. */
47038fd1498Szrj if (node->native_rtl_p ())
47138fd1498Szrj node->force_output = 1;
47238fd1498Szrj
47338fd1498Szrj /* When not optimizing, also output the static functions. (see
47438fd1498Szrj PR24561), but don't do so for always_inline functions, functions
47538fd1498Szrj declared inline and nested functions. These were optimized out
47638fd1498Szrj in the original implementation and it is unclear whether we want
47738fd1498Szrj to change the behavior here. */
47838fd1498Szrj if (((!opt_for_fn (decl, optimize) || flag_keep_static_functions
47938fd1498Szrj || node->no_reorder)
48038fd1498Szrj && !node->cpp_implicit_alias
48138fd1498Szrj && !DECL_DISREGARD_INLINE_LIMITS (decl)
48238fd1498Szrj && !DECL_DECLARED_INLINE_P (decl)
48338fd1498Szrj && !(DECL_CONTEXT (decl)
48438fd1498Szrj && TREE_CODE (DECL_CONTEXT (decl)) == FUNCTION_DECL))
48538fd1498Szrj && !DECL_COMDAT (decl) && !DECL_EXTERNAL (decl))
48638fd1498Szrj node->force_output = 1;
48738fd1498Szrj
48838fd1498Szrj /* If we've not yet emitted decl, tell the debug info about it. */
48938fd1498Szrj if (!TREE_ASM_WRITTEN (decl))
49038fd1498Szrj (*debug_hooks->deferred_inline_function) (decl);
49138fd1498Szrj
49238fd1498Szrj if (!no_collect)
49338fd1498Szrj ggc_collect ();
49438fd1498Szrj
49538fd1498Szrj if (symtab->state == CONSTRUCTION
49638fd1498Szrj && (node->needed_p () || node->referred_to_p ()))
49738fd1498Szrj enqueue_node (node);
49838fd1498Szrj }
49938fd1498Szrj
50038fd1498Szrj /* Add the function FNDECL to the call graph.
50138fd1498Szrj Unlike finalize_function, this function is intended to be used
50238fd1498Szrj by middle end and allows insertion of new function at arbitrary point
50338fd1498Szrj of compilation. The function can be either in high, low or SSA form
50438fd1498Szrj GIMPLE.
50538fd1498Szrj
50638fd1498Szrj The function is assumed to be reachable and have address taken (so no
50738fd1498Szrj API breaking optimizations are performed on it).
50838fd1498Szrj
50938fd1498Szrj Main work done by this function is to enqueue the function for later
51038fd1498Szrj processing to avoid need the passes to be re-entrant. */
51138fd1498Szrj
51238fd1498Szrj void
add_new_function(tree fndecl,bool lowered)51338fd1498Szrj cgraph_node::add_new_function (tree fndecl, bool lowered)
51438fd1498Szrj {
51538fd1498Szrj gcc::pass_manager *passes = g->get_passes ();
51638fd1498Szrj cgraph_node *node;
51738fd1498Szrj
51838fd1498Szrj if (dump_file)
51938fd1498Szrj {
52038fd1498Szrj struct function *fn = DECL_STRUCT_FUNCTION (fndecl);
52138fd1498Szrj const char *function_type = ((gimple_has_body_p (fndecl))
52238fd1498Szrj ? (lowered
52338fd1498Szrj ? (gimple_in_ssa_p (fn)
52438fd1498Szrj ? "ssa gimple"
52538fd1498Szrj : "low gimple")
52638fd1498Szrj : "high gimple")
52738fd1498Szrj : "to-be-gimplified");
52838fd1498Szrj fprintf (dump_file,
52938fd1498Szrj "Added new %s function %s to callgraph\n",
53038fd1498Szrj function_type,
53138fd1498Szrj fndecl_name (fndecl));
53238fd1498Szrj }
53338fd1498Szrj
53438fd1498Szrj switch (symtab->state)
53538fd1498Szrj {
53638fd1498Szrj case PARSING:
53738fd1498Szrj cgraph_node::finalize_function (fndecl, false);
53838fd1498Szrj break;
53938fd1498Szrj case CONSTRUCTION:
54038fd1498Szrj /* Just enqueue function to be processed at nearest occurrence. */
54138fd1498Szrj node = cgraph_node::get_create (fndecl);
54238fd1498Szrj if (lowered)
54338fd1498Szrj node->lowered = true;
54438fd1498Szrj cgraph_new_nodes.safe_push (node);
54538fd1498Szrj break;
54638fd1498Szrj
54738fd1498Szrj case IPA:
54838fd1498Szrj case IPA_SSA:
54938fd1498Szrj case IPA_SSA_AFTER_INLINING:
55038fd1498Szrj case EXPANSION:
55138fd1498Szrj /* Bring the function into finalized state and enqueue for later
55238fd1498Szrj analyzing and compilation. */
55338fd1498Szrj node = cgraph_node::get_create (fndecl);
55438fd1498Szrj node->local.local = false;
55538fd1498Szrj node->definition = true;
55638fd1498Szrj node->force_output = true;
55738fd1498Szrj if (TREE_PUBLIC (fndecl))
55838fd1498Szrj node->externally_visible = true;
55938fd1498Szrj if (!lowered && symtab->state == EXPANSION)
56038fd1498Szrj {
56138fd1498Szrj push_cfun (DECL_STRUCT_FUNCTION (fndecl));
56238fd1498Szrj gimple_register_cfg_hooks ();
56338fd1498Szrj bitmap_obstack_initialize (NULL);
56438fd1498Szrj execute_pass_list (cfun, passes->all_lowering_passes);
56538fd1498Szrj passes->execute_early_local_passes ();
56638fd1498Szrj bitmap_obstack_release (NULL);
56738fd1498Szrj pop_cfun ();
56838fd1498Szrj
56938fd1498Szrj lowered = true;
57038fd1498Szrj }
57138fd1498Szrj if (lowered)
57238fd1498Szrj node->lowered = true;
57338fd1498Szrj cgraph_new_nodes.safe_push (node);
57438fd1498Szrj break;
57538fd1498Szrj
57638fd1498Szrj case FINISHED:
57738fd1498Szrj /* At the very end of compilation we have to do all the work up
57838fd1498Szrj to expansion. */
57938fd1498Szrj node = cgraph_node::create (fndecl);
58038fd1498Szrj if (lowered)
58138fd1498Szrj node->lowered = true;
58238fd1498Szrj node->definition = true;
58338fd1498Szrj node->analyze ();
58438fd1498Szrj push_cfun (DECL_STRUCT_FUNCTION (fndecl));
58538fd1498Szrj gimple_register_cfg_hooks ();
58638fd1498Szrj bitmap_obstack_initialize (NULL);
58738fd1498Szrj if (!gimple_in_ssa_p (DECL_STRUCT_FUNCTION (fndecl)))
58838fd1498Szrj g->get_passes ()->execute_early_local_passes ();
58938fd1498Szrj bitmap_obstack_release (NULL);
59038fd1498Szrj pop_cfun ();
59138fd1498Szrj node->expand ();
59238fd1498Szrj break;
59338fd1498Szrj
59438fd1498Szrj default:
59538fd1498Szrj gcc_unreachable ();
59638fd1498Szrj }
59738fd1498Szrj
59838fd1498Szrj /* Set a personality if required and we already passed EH lowering. */
59938fd1498Szrj if (lowered
60038fd1498Szrj && (function_needs_eh_personality (DECL_STRUCT_FUNCTION (fndecl))
60138fd1498Szrj == eh_personality_lang))
60238fd1498Szrj DECL_FUNCTION_PERSONALITY (fndecl) = lang_hooks.eh_personality ();
60338fd1498Szrj }
60438fd1498Szrj
60538fd1498Szrj /* Analyze the function scheduled to be output. */
60638fd1498Szrj void
analyze(void)60738fd1498Szrj cgraph_node::analyze (void)
60838fd1498Szrj {
60938fd1498Szrj if (native_rtl_p ())
61038fd1498Szrj {
61138fd1498Szrj analyzed = true;
61238fd1498Szrj return;
61338fd1498Szrj }
61438fd1498Szrj
61538fd1498Szrj tree decl = this->decl;
61638fd1498Szrj location_t saved_loc = input_location;
61738fd1498Szrj input_location = DECL_SOURCE_LOCATION (decl);
61838fd1498Szrj
61938fd1498Szrj if (thunk.thunk_p)
62038fd1498Szrj {
62138fd1498Szrj cgraph_node *t = cgraph_node::get (thunk.alias);
62238fd1498Szrj
62338fd1498Szrj create_edge (t, NULL, t->count);
62438fd1498Szrj callees->can_throw_external = !TREE_NOTHROW (t->decl);
62538fd1498Szrj /* Target code in expand_thunk may need the thunk's target
62638fd1498Szrj to be analyzed, so recurse here. */
62738fd1498Szrj if (!t->analyzed)
62838fd1498Szrj t->analyze ();
62938fd1498Szrj if (t->alias)
63038fd1498Szrj {
63138fd1498Szrj t = t->get_alias_target ();
63238fd1498Szrj if (!t->analyzed)
63338fd1498Szrj t->analyze ();
63438fd1498Szrj }
63538fd1498Szrj if (!expand_thunk (false, false))
63638fd1498Szrj {
63738fd1498Szrj thunk.alias = NULL;
63838fd1498Szrj return;
63938fd1498Szrj }
64038fd1498Szrj thunk.alias = NULL;
64138fd1498Szrj }
64238fd1498Szrj if (alias)
64338fd1498Szrj resolve_alias (cgraph_node::get (alias_target), transparent_alias);
64438fd1498Szrj else if (dispatcher_function)
64538fd1498Szrj {
64638fd1498Szrj /* Generate the dispatcher body of multi-versioned functions. */
64738fd1498Szrj cgraph_function_version_info *dispatcher_version_info
64838fd1498Szrj = function_version ();
64938fd1498Szrj if (dispatcher_version_info != NULL
65038fd1498Szrj && (dispatcher_version_info->dispatcher_resolver
65138fd1498Szrj == NULL_TREE))
65238fd1498Szrj {
65338fd1498Szrj tree resolver = NULL_TREE;
65438fd1498Szrj gcc_assert (targetm.generate_version_dispatcher_body);
65538fd1498Szrj resolver = targetm.generate_version_dispatcher_body (this);
65638fd1498Szrj gcc_assert (resolver != NULL_TREE);
65738fd1498Szrj }
65838fd1498Szrj }
65938fd1498Szrj else
66038fd1498Szrj {
66138fd1498Szrj push_cfun (DECL_STRUCT_FUNCTION (decl));
66238fd1498Szrj
66338fd1498Szrj assign_assembler_name_if_needed (decl);
66438fd1498Szrj
66538fd1498Szrj /* Make sure to gimplify bodies only once. During analyzing a
66638fd1498Szrj function we lower it, which will require gimplified nested
66738fd1498Szrj functions, so we can end up here with an already gimplified
66838fd1498Szrj body. */
66938fd1498Szrj if (!gimple_has_body_p (decl))
67038fd1498Szrj gimplify_function_tree (decl);
67138fd1498Szrj
67238fd1498Szrj /* Lower the function. */
67338fd1498Szrj if (!lowered)
67438fd1498Szrj {
67538fd1498Szrj if (nested)
67638fd1498Szrj lower_nested_functions (decl);
67738fd1498Szrj gcc_assert (!nested);
67838fd1498Szrj
67938fd1498Szrj gimple_register_cfg_hooks ();
68038fd1498Szrj bitmap_obstack_initialize (NULL);
68138fd1498Szrj execute_pass_list (cfun, g->get_passes ()->all_lowering_passes);
68238fd1498Szrj free_dominance_info (CDI_POST_DOMINATORS);
68338fd1498Szrj free_dominance_info (CDI_DOMINATORS);
68438fd1498Szrj compact_blocks ();
68538fd1498Szrj bitmap_obstack_release (NULL);
68638fd1498Szrj lowered = true;
68738fd1498Szrj }
68838fd1498Szrj
68938fd1498Szrj pop_cfun ();
69038fd1498Szrj }
69138fd1498Szrj analyzed = true;
69238fd1498Szrj
69338fd1498Szrj input_location = saved_loc;
69438fd1498Szrj }
69538fd1498Szrj
69638fd1498Szrj /* C++ frontend produce same body aliases all over the place, even before PCH
69738fd1498Szrj gets streamed out. It relies on us linking the aliases with their function
69838fd1498Szrj in order to do the fixups, but ipa-ref is not PCH safe. Consequentely we
69938fd1498Szrj first produce aliases without links, but once C++ FE is sure he won't sream
70038fd1498Szrj PCH we build the links via this function. */
70138fd1498Szrj
70238fd1498Szrj void
process_same_body_aliases(void)70338fd1498Szrj symbol_table::process_same_body_aliases (void)
70438fd1498Szrj {
70538fd1498Szrj symtab_node *node;
70638fd1498Szrj FOR_EACH_SYMBOL (node)
70738fd1498Szrj if (node->cpp_implicit_alias && !node->analyzed)
70838fd1498Szrj node->resolve_alias
70938fd1498Szrj (VAR_P (node->alias_target)
71038fd1498Szrj ? (symtab_node *)varpool_node::get_create (node->alias_target)
71138fd1498Szrj : (symtab_node *)cgraph_node::get_create (node->alias_target));
71238fd1498Szrj cpp_implicit_aliases_done = true;
71338fd1498Szrj }
71438fd1498Szrj
71538fd1498Szrj /* Process attributes common for vars and functions. */
71638fd1498Szrj
71738fd1498Szrj static void
process_common_attributes(symtab_node * node,tree decl)71838fd1498Szrj process_common_attributes (symtab_node *node, tree decl)
71938fd1498Szrj {
72038fd1498Szrj tree weakref = lookup_attribute ("weakref", DECL_ATTRIBUTES (decl));
72138fd1498Szrj
72238fd1498Szrj if (weakref && !lookup_attribute ("alias", DECL_ATTRIBUTES (decl)))
72338fd1498Szrj {
72438fd1498Szrj warning_at (DECL_SOURCE_LOCATION (decl), OPT_Wattributes,
72538fd1498Szrj "%<weakref%> attribute should be accompanied with"
72638fd1498Szrj " an %<alias%> attribute");
72738fd1498Szrj DECL_WEAK (decl) = 0;
72838fd1498Szrj DECL_ATTRIBUTES (decl) = remove_attribute ("weakref",
72938fd1498Szrj DECL_ATTRIBUTES (decl));
73038fd1498Szrj }
73138fd1498Szrj
73238fd1498Szrj if (lookup_attribute ("no_reorder", DECL_ATTRIBUTES (decl)))
73338fd1498Szrj node->no_reorder = 1;
73438fd1498Szrj }
73538fd1498Szrj
73638fd1498Szrj /* Look for externally_visible and used attributes and mark cgraph nodes
73738fd1498Szrj accordingly.
73838fd1498Szrj
73938fd1498Szrj We cannot mark the nodes at the point the attributes are processed (in
74038fd1498Szrj handle_*_attribute) because the copy of the declarations available at that
74138fd1498Szrj point may not be canonical. For example, in:
74238fd1498Szrj
74338fd1498Szrj void f();
74438fd1498Szrj void f() __attribute__((used));
74538fd1498Szrj
74638fd1498Szrj the declaration we see in handle_used_attribute will be the second
74738fd1498Szrj declaration -- but the front end will subsequently merge that declaration
74838fd1498Szrj with the original declaration and discard the second declaration.
74938fd1498Szrj
75038fd1498Szrj Furthermore, we can't mark these nodes in finalize_function because:
75138fd1498Szrj
75238fd1498Szrj void f() {}
75338fd1498Szrj void f() __attribute__((externally_visible));
75438fd1498Szrj
75538fd1498Szrj is valid.
75638fd1498Szrj
75738fd1498Szrj So, we walk the nodes at the end of the translation unit, applying the
75838fd1498Szrj attributes at that point. */
75938fd1498Szrj
76038fd1498Szrj static void
process_function_and_variable_attributes(cgraph_node * first,varpool_node * first_var)76138fd1498Szrj process_function_and_variable_attributes (cgraph_node *first,
76238fd1498Szrj varpool_node *first_var)
76338fd1498Szrj {
76438fd1498Szrj cgraph_node *node;
76538fd1498Szrj varpool_node *vnode;
76638fd1498Szrj
76738fd1498Szrj for (node = symtab->first_function (); node != first;
76838fd1498Szrj node = symtab->next_function (node))
76938fd1498Szrj {
77038fd1498Szrj tree decl = node->decl;
77138fd1498Szrj if (DECL_PRESERVE_P (decl))
77238fd1498Szrj node->mark_force_output ();
77338fd1498Szrj else if (lookup_attribute ("externally_visible", DECL_ATTRIBUTES (decl)))
77438fd1498Szrj {
77538fd1498Szrj if (! TREE_PUBLIC (node->decl))
77638fd1498Szrj warning_at (DECL_SOURCE_LOCATION (node->decl), OPT_Wattributes,
77738fd1498Szrj "%<externally_visible%>"
77838fd1498Szrj " attribute have effect only on public objects");
77938fd1498Szrj }
78038fd1498Szrj if (lookup_attribute ("weakref", DECL_ATTRIBUTES (decl))
78138fd1498Szrj && (node->definition && !node->alias))
78238fd1498Szrj {
78338fd1498Szrj warning_at (DECL_SOURCE_LOCATION (node->decl), OPT_Wattributes,
78438fd1498Szrj "%<weakref%> attribute ignored"
78538fd1498Szrj " because function is defined");
78638fd1498Szrj DECL_WEAK (decl) = 0;
78738fd1498Szrj DECL_ATTRIBUTES (decl) = remove_attribute ("weakref",
78838fd1498Szrj DECL_ATTRIBUTES (decl));
78938fd1498Szrj }
79038fd1498Szrj
79138fd1498Szrj if (lookup_attribute ("always_inline", DECL_ATTRIBUTES (decl))
79238fd1498Szrj && !DECL_DECLARED_INLINE_P (decl)
79338fd1498Szrj /* redefining extern inline function makes it DECL_UNINLINABLE. */
79438fd1498Szrj && !DECL_UNINLINABLE (decl))
79538fd1498Szrj warning_at (DECL_SOURCE_LOCATION (decl), OPT_Wattributes,
79638fd1498Szrj "always_inline function might not be inlinable");
79738fd1498Szrj
79838fd1498Szrj process_common_attributes (node, decl);
79938fd1498Szrj }
80038fd1498Szrj for (vnode = symtab->first_variable (); vnode != first_var;
80138fd1498Szrj vnode = symtab->next_variable (vnode))
80238fd1498Szrj {
80338fd1498Szrj tree decl = vnode->decl;
80438fd1498Szrj if (DECL_EXTERNAL (decl)
80538fd1498Szrj && DECL_INITIAL (decl))
80638fd1498Szrj varpool_node::finalize_decl (decl);
80738fd1498Szrj if (DECL_PRESERVE_P (decl))
80838fd1498Szrj vnode->force_output = true;
80938fd1498Szrj else if (lookup_attribute ("externally_visible", DECL_ATTRIBUTES (decl)))
81038fd1498Szrj {
81138fd1498Szrj if (! TREE_PUBLIC (vnode->decl))
81238fd1498Szrj warning_at (DECL_SOURCE_LOCATION (vnode->decl), OPT_Wattributes,
81338fd1498Szrj "%<externally_visible%>"
81438fd1498Szrj " attribute have effect only on public objects");
81538fd1498Szrj }
81638fd1498Szrj if (lookup_attribute ("weakref", DECL_ATTRIBUTES (decl))
81738fd1498Szrj && vnode->definition
81838fd1498Szrj && DECL_INITIAL (decl))
81938fd1498Szrj {
82038fd1498Szrj warning_at (DECL_SOURCE_LOCATION (vnode->decl), OPT_Wattributes,
82138fd1498Szrj "%<weakref%> attribute ignored"
82238fd1498Szrj " because variable is initialized");
82338fd1498Szrj DECL_WEAK (decl) = 0;
82438fd1498Szrj DECL_ATTRIBUTES (decl) = remove_attribute ("weakref",
82538fd1498Szrj DECL_ATTRIBUTES (decl));
82638fd1498Szrj }
82738fd1498Szrj process_common_attributes (vnode, decl);
82838fd1498Szrj }
82938fd1498Szrj }
83038fd1498Szrj
83138fd1498Szrj /* Mark DECL as finalized. By finalizing the declaration, frontend instruct the
83238fd1498Szrj middle end to output the variable to asm file, if needed or externally
83338fd1498Szrj visible. */
83438fd1498Szrj
83538fd1498Szrj void
finalize_decl(tree decl)83638fd1498Szrj varpool_node::finalize_decl (tree decl)
83738fd1498Szrj {
83838fd1498Szrj varpool_node *node = varpool_node::get_create (decl);
83938fd1498Szrj
84038fd1498Szrj gcc_assert (TREE_STATIC (decl) || DECL_EXTERNAL (decl));
84138fd1498Szrj
84238fd1498Szrj if (node->definition)
84338fd1498Szrj return;
84438fd1498Szrj /* Set definition first before calling notice_global_symbol so that
84538fd1498Szrj it is available to notice_global_symbol. */
84638fd1498Szrj node->definition = true;
84738fd1498Szrj notice_global_symbol (decl);
84838fd1498Szrj if (!flag_toplevel_reorder)
84938fd1498Szrj node->no_reorder = true;
85038fd1498Szrj if (TREE_THIS_VOLATILE (decl) || DECL_PRESERVE_P (decl)
85138fd1498Szrj /* Traditionally we do not eliminate static variables when not
85238fd1498Szrj optimizing and when not doing toplevel reoder. */
85338fd1498Szrj || (node->no_reorder && !DECL_COMDAT (node->decl)
85438fd1498Szrj && !DECL_ARTIFICIAL (node->decl)))
85538fd1498Szrj node->force_output = true;
85638fd1498Szrj
85738fd1498Szrj if (symtab->state == CONSTRUCTION
85838fd1498Szrj && (node->needed_p () || node->referred_to_p ()))
85938fd1498Szrj enqueue_node (node);
86038fd1498Szrj if (symtab->state >= IPA_SSA)
86138fd1498Szrj node->analyze ();
86238fd1498Szrj /* Some frontends produce various interface variables after compilation
86338fd1498Szrj finished. */
86438fd1498Szrj if (symtab->state == FINISHED
86538fd1498Szrj || (node->no_reorder
86638fd1498Szrj && symtab->state == EXPANSION))
86738fd1498Szrj node->assemble_decl ();
86838fd1498Szrj
86938fd1498Szrj if (DECL_INITIAL (decl))
87038fd1498Szrj chkp_register_var_initializer (decl);
87138fd1498Szrj }
87238fd1498Szrj
87338fd1498Szrj /* EDGE is an polymorphic call. Mark all possible targets as reachable
87438fd1498Szrj and if there is only one target, perform trivial devirtualization.
87538fd1498Szrj REACHABLE_CALL_TARGETS collects target lists we already walked to
87638fd1498Szrj avoid udplicate work. */
87738fd1498Szrj
87838fd1498Szrj static void
walk_polymorphic_call_targets(hash_set<void * > * reachable_call_targets,cgraph_edge * edge)87938fd1498Szrj walk_polymorphic_call_targets (hash_set<void *> *reachable_call_targets,
88038fd1498Szrj cgraph_edge *edge)
88138fd1498Szrj {
88238fd1498Szrj unsigned int i;
88338fd1498Szrj void *cache_token;
88438fd1498Szrj bool final;
88538fd1498Szrj vec <cgraph_node *>targets
88638fd1498Szrj = possible_polymorphic_call_targets
88738fd1498Szrj (edge, &final, &cache_token);
88838fd1498Szrj
88938fd1498Szrj if (!reachable_call_targets->add (cache_token))
89038fd1498Szrj {
89138fd1498Szrj if (symtab->dump_file)
89238fd1498Szrj dump_possible_polymorphic_call_targets
89338fd1498Szrj (symtab->dump_file, edge);
89438fd1498Szrj
89538fd1498Szrj for (i = 0; i < targets.length (); i++)
89638fd1498Szrj {
89738fd1498Szrj /* Do not bother to mark virtual methods in anonymous namespace;
89838fd1498Szrj either we will find use of virtual table defining it, or it is
89938fd1498Szrj unused. */
90038fd1498Szrj if (targets[i]->definition
90138fd1498Szrj && TREE_CODE
90238fd1498Szrj (TREE_TYPE (targets[i]->decl))
90338fd1498Szrj == METHOD_TYPE
90438fd1498Szrj && !type_in_anonymous_namespace_p
90538fd1498Szrj (TYPE_METHOD_BASETYPE (TREE_TYPE (targets[i]->decl))))
90638fd1498Szrj enqueue_node (targets[i]);
90738fd1498Szrj }
90838fd1498Szrj }
90938fd1498Szrj
91038fd1498Szrj /* Very trivial devirtualization; when the type is
91138fd1498Szrj final or anonymous (so we know all its derivation)
91238fd1498Szrj and there is only one possible virtual call target,
91338fd1498Szrj make the edge direct. */
91438fd1498Szrj if (final)
91538fd1498Szrj {
91638fd1498Szrj if (targets.length () <= 1 && dbg_cnt (devirt))
91738fd1498Szrj {
91838fd1498Szrj cgraph_node *target;
91938fd1498Szrj if (targets.length () == 1)
92038fd1498Szrj target = targets[0];
92138fd1498Szrj else
92238fd1498Szrj target = cgraph_node::create
92338fd1498Szrj (builtin_decl_implicit (BUILT_IN_UNREACHABLE));
92438fd1498Szrj
92538fd1498Szrj if (symtab->dump_file)
92638fd1498Szrj {
92738fd1498Szrj fprintf (symtab->dump_file,
92838fd1498Szrj "Devirtualizing call: ");
92938fd1498Szrj print_gimple_stmt (symtab->dump_file,
93038fd1498Szrj edge->call_stmt, 0,
93138fd1498Szrj TDF_SLIM);
93238fd1498Szrj }
93338fd1498Szrj if (dump_enabled_p ())
93438fd1498Szrj {
93538fd1498Szrj location_t locus = gimple_location_safe (edge->call_stmt);
93638fd1498Szrj dump_printf_loc (MSG_OPTIMIZED_LOCATIONS, locus,
93738fd1498Szrj "devirtualizing call in %s to %s\n",
93838fd1498Szrj edge->caller->name (), target->name ());
93938fd1498Szrj }
94038fd1498Szrj
94138fd1498Szrj edge->make_direct (target);
94238fd1498Szrj edge->redirect_call_stmt_to_callee ();
94338fd1498Szrj
94438fd1498Szrj /* Call to __builtin_unreachable shouldn't be instrumented. */
94538fd1498Szrj if (!targets.length ())
94638fd1498Szrj gimple_call_set_with_bounds (edge->call_stmt, false);
94738fd1498Szrj
94838fd1498Szrj if (symtab->dump_file)
94938fd1498Szrj {
95038fd1498Szrj fprintf (symtab->dump_file,
95138fd1498Szrj "Devirtualized as: ");
95238fd1498Szrj print_gimple_stmt (symtab->dump_file,
95338fd1498Szrj edge->call_stmt, 0,
95438fd1498Szrj TDF_SLIM);
95538fd1498Szrj }
95638fd1498Szrj }
95738fd1498Szrj }
95838fd1498Szrj }
95938fd1498Szrj
96038fd1498Szrj /* Issue appropriate warnings for the global declaration DECL. */
96138fd1498Szrj
96238fd1498Szrj static void
check_global_declaration(symtab_node * snode)96338fd1498Szrj check_global_declaration (symtab_node *snode)
96438fd1498Szrj {
96538fd1498Szrj const char *decl_file;
96638fd1498Szrj tree decl = snode->decl;
96738fd1498Szrj
96838fd1498Szrj /* Warn about any function declared static but not defined. We don't
96938fd1498Szrj warn about variables, because many programs have static variables
97038fd1498Szrj that exist only to get some text into the object file. */
97138fd1498Szrj if (TREE_CODE (decl) == FUNCTION_DECL
97238fd1498Szrj && DECL_INITIAL (decl) == 0
97338fd1498Szrj && DECL_EXTERNAL (decl)
97438fd1498Szrj && ! DECL_ARTIFICIAL (decl)
97538fd1498Szrj && ! TREE_NO_WARNING (decl)
97638fd1498Szrj && ! TREE_PUBLIC (decl)
97738fd1498Szrj && (warn_unused_function
97838fd1498Szrj || snode->referred_to_p (/*include_self=*/false)))
97938fd1498Szrj {
98038fd1498Szrj if (snode->referred_to_p (/*include_self=*/false))
98138fd1498Szrj pedwarn (input_location, 0, "%q+F used but never defined", decl);
98238fd1498Szrj else
98338fd1498Szrj warning (OPT_Wunused_function, "%q+F declared %<static%> but never defined", decl);
98438fd1498Szrj /* This symbol is effectively an "extern" declaration now. */
98538fd1498Szrj TREE_PUBLIC (decl) = 1;
98638fd1498Szrj }
98738fd1498Szrj
98838fd1498Szrj /* Warn about static fns or vars defined but not used. */
98938fd1498Szrj if (((warn_unused_function && TREE_CODE (decl) == FUNCTION_DECL)
99038fd1498Szrj || (((warn_unused_variable && ! TREE_READONLY (decl))
99138fd1498Szrj || (warn_unused_const_variable > 0 && TREE_READONLY (decl)
99238fd1498Szrj && (warn_unused_const_variable == 2
99338fd1498Szrj || (main_input_filename != NULL
99438fd1498Szrj && (decl_file = DECL_SOURCE_FILE (decl)) != NULL
99538fd1498Szrj && filename_cmp (main_input_filename,
99638fd1498Szrj decl_file) == 0))))
99738fd1498Szrj && VAR_P (decl)))
99838fd1498Szrj && ! DECL_IN_SYSTEM_HEADER (decl)
99938fd1498Szrj && ! snode->referred_to_p (/*include_self=*/false)
100038fd1498Szrj /* This TREE_USED check is needed in addition to referred_to_p
100138fd1498Szrj above, because the `__unused__' attribute is not being
100238fd1498Szrj considered for referred_to_p. */
100338fd1498Szrj && ! TREE_USED (decl)
100438fd1498Szrj /* The TREE_USED bit for file-scope decls is kept in the identifier,
100538fd1498Szrj to handle multiple external decls in different scopes. */
100638fd1498Szrj && ! (DECL_NAME (decl) && TREE_USED (DECL_NAME (decl)))
100738fd1498Szrj && ! DECL_EXTERNAL (decl)
100838fd1498Szrj && ! DECL_ARTIFICIAL (decl)
100938fd1498Szrj && ! DECL_ABSTRACT_ORIGIN (decl)
101038fd1498Szrj && ! TREE_PUBLIC (decl)
101138fd1498Szrj /* A volatile variable might be used in some non-obvious way. */
101238fd1498Szrj && (! VAR_P (decl) || ! TREE_THIS_VOLATILE (decl))
101338fd1498Szrj /* Global register variables must be declared to reserve them. */
101438fd1498Szrj && ! (VAR_P (decl) && DECL_REGISTER (decl))
101538fd1498Szrj /* Global ctors and dtors are called by the runtime. */
101638fd1498Szrj && (TREE_CODE (decl) != FUNCTION_DECL
101738fd1498Szrj || (!DECL_STATIC_CONSTRUCTOR (decl)
101838fd1498Szrj && !DECL_STATIC_DESTRUCTOR (decl)))
101938fd1498Szrj /* Otherwise, ask the language. */
102038fd1498Szrj && lang_hooks.decls.warn_unused_global (decl))
102138fd1498Szrj warning_at (DECL_SOURCE_LOCATION (decl),
102238fd1498Szrj (TREE_CODE (decl) == FUNCTION_DECL)
102338fd1498Szrj ? OPT_Wunused_function
102438fd1498Szrj : (TREE_READONLY (decl)
102538fd1498Szrj ? OPT_Wunused_const_variable_
102638fd1498Szrj : OPT_Wunused_variable),
102738fd1498Szrj "%qD defined but not used", decl);
102838fd1498Szrj }
102938fd1498Szrj
103038fd1498Szrj /* Discover all functions and variables that are trivially needed, analyze
103138fd1498Szrj them as well as all functions and variables referred by them */
103238fd1498Szrj static cgraph_node *first_analyzed;
103338fd1498Szrj static varpool_node *first_analyzed_var;
103438fd1498Szrj
103538fd1498Szrj /* FIRST_TIME is set to TRUE for the first time we are called for a
103638fd1498Szrj translation unit from finalize_compilation_unit() or false
103738fd1498Szrj otherwise. */
103838fd1498Szrj
103938fd1498Szrj static void
analyze_functions(bool first_time)104038fd1498Szrj analyze_functions (bool first_time)
104138fd1498Szrj {
104238fd1498Szrj /* Keep track of already processed nodes when called multiple times for
104338fd1498Szrj intermodule optimization. */
104438fd1498Szrj cgraph_node *first_handled = first_analyzed;
104538fd1498Szrj varpool_node *first_handled_var = first_analyzed_var;
104638fd1498Szrj hash_set<void *> reachable_call_targets;
104738fd1498Szrj
104838fd1498Szrj symtab_node *node;
104938fd1498Szrj symtab_node *next;
105038fd1498Szrj int i;
105138fd1498Szrj ipa_ref *ref;
105238fd1498Szrj bool changed = true;
105338fd1498Szrj location_t saved_loc = input_location;
105438fd1498Szrj
105538fd1498Szrj bitmap_obstack_initialize (NULL);
105638fd1498Szrj symtab->state = CONSTRUCTION;
105738fd1498Szrj input_location = UNKNOWN_LOCATION;
105838fd1498Szrj
105938fd1498Szrj /* Ugly, but the fixup can not happen at a time same body alias is created;
106038fd1498Szrj C++ FE is confused about the COMDAT groups being right. */
106138fd1498Szrj if (symtab->cpp_implicit_aliases_done)
106238fd1498Szrj FOR_EACH_SYMBOL (node)
106338fd1498Szrj if (node->cpp_implicit_alias)
106438fd1498Szrj node->fixup_same_cpp_alias_visibility (node->get_alias_target ());
106538fd1498Szrj build_type_inheritance_graph ();
106638fd1498Szrj
106738fd1498Szrj /* Analysis adds static variables that in turn adds references to new functions.
106838fd1498Szrj So we need to iterate the process until it stabilize. */
106938fd1498Szrj while (changed)
107038fd1498Szrj {
107138fd1498Szrj changed = false;
107238fd1498Szrj process_function_and_variable_attributes (first_analyzed,
107338fd1498Szrj first_analyzed_var);
107438fd1498Szrj
107538fd1498Szrj /* First identify the trivially needed symbols. */
107638fd1498Szrj for (node = symtab->first_symbol ();
107738fd1498Szrj node != first_analyzed
107838fd1498Szrj && node != first_analyzed_var; node = node->next)
107938fd1498Szrj {
108038fd1498Szrj /* Convert COMDAT group designators to IDENTIFIER_NODEs. */
108138fd1498Szrj node->get_comdat_group_id ();
108238fd1498Szrj if (node->needed_p ())
108338fd1498Szrj {
108438fd1498Szrj enqueue_node (node);
108538fd1498Szrj if (!changed && symtab->dump_file)
108638fd1498Szrj fprintf (symtab->dump_file, "Trivially needed symbols:");
108738fd1498Szrj changed = true;
108838fd1498Szrj if (symtab->dump_file)
108938fd1498Szrj fprintf (symtab->dump_file, " %s", node->asm_name ());
109038fd1498Szrj if (!changed && symtab->dump_file)
109138fd1498Szrj fprintf (symtab->dump_file, "\n");
109238fd1498Szrj }
109338fd1498Szrj if (node == first_analyzed
109438fd1498Szrj || node == first_analyzed_var)
109538fd1498Szrj break;
109638fd1498Szrj }
109738fd1498Szrj symtab->process_new_functions ();
109838fd1498Szrj first_analyzed_var = symtab->first_variable ();
109938fd1498Szrj first_analyzed = symtab->first_function ();
110038fd1498Szrj
110138fd1498Szrj if (changed && symtab->dump_file)
110238fd1498Szrj fprintf (symtab->dump_file, "\n");
110338fd1498Szrj
110438fd1498Szrj /* Lower representation, build callgraph edges and references for all trivially
110538fd1498Szrj needed symbols and all symbols referred by them. */
110638fd1498Szrj while (queued_nodes != &symtab_terminator)
110738fd1498Szrj {
110838fd1498Szrj changed = true;
110938fd1498Szrj node = queued_nodes;
111038fd1498Szrj queued_nodes = (symtab_node *)queued_nodes->aux;
111138fd1498Szrj cgraph_node *cnode = dyn_cast <cgraph_node *> (node);
111238fd1498Szrj if (cnode && cnode->definition)
111338fd1498Szrj {
111438fd1498Szrj cgraph_edge *edge;
111538fd1498Szrj tree decl = cnode->decl;
111638fd1498Szrj
111738fd1498Szrj /* ??? It is possible to create extern inline function
111838fd1498Szrj and later using weak alias attribute to kill its body.
111938fd1498Szrj See gcc.c-torture/compile/20011119-1.c */
112038fd1498Szrj if (!DECL_STRUCT_FUNCTION (decl)
112138fd1498Szrj && !cnode->alias
112238fd1498Szrj && !cnode->thunk.thunk_p
112338fd1498Szrj && !cnode->dispatcher_function)
112438fd1498Szrj {
112538fd1498Szrj cnode->reset ();
112638fd1498Szrj cnode->local.redefined_extern_inline = true;
112738fd1498Szrj continue;
112838fd1498Szrj }
112938fd1498Szrj
113038fd1498Szrj if (!cnode->analyzed)
113138fd1498Szrj cnode->analyze ();
113238fd1498Szrj
113338fd1498Szrj for (edge = cnode->callees; edge; edge = edge->next_callee)
113438fd1498Szrj if (edge->callee->definition
113538fd1498Szrj && (!DECL_EXTERNAL (edge->callee->decl)
113638fd1498Szrj /* When not optimizing, do not try to analyze extern
113738fd1498Szrj inline functions. Doing so is pointless. */
113838fd1498Szrj || opt_for_fn (edge->callee->decl, optimize)
113938fd1498Szrj /* Weakrefs needs to be preserved. */
114038fd1498Szrj || edge->callee->alias
114138fd1498Szrj /* always_inline functions are inlined aven at -O0. */
114238fd1498Szrj || lookup_attribute
114338fd1498Szrj ("always_inline",
114438fd1498Szrj DECL_ATTRIBUTES (edge->callee->decl))
114538fd1498Szrj /* Multiversioned functions needs the dispatcher to
114638fd1498Szrj be produced locally even for extern functions. */
114738fd1498Szrj || edge->callee->function_version ()))
114838fd1498Szrj enqueue_node (edge->callee);
114938fd1498Szrj if (opt_for_fn (cnode->decl, optimize)
115038fd1498Szrj && opt_for_fn (cnode->decl, flag_devirtualize))
115138fd1498Szrj {
115238fd1498Szrj cgraph_edge *next;
115338fd1498Szrj
115438fd1498Szrj for (edge = cnode->indirect_calls; edge; edge = next)
115538fd1498Szrj {
115638fd1498Szrj next = edge->next_callee;
115738fd1498Szrj if (edge->indirect_info->polymorphic)
115838fd1498Szrj walk_polymorphic_call_targets (&reachable_call_targets,
115938fd1498Szrj edge);
116038fd1498Szrj }
116138fd1498Szrj }
116238fd1498Szrj
116338fd1498Szrj /* If decl is a clone of an abstract function,
116438fd1498Szrj mark that abstract function so that we don't release its body.
116538fd1498Szrj The DECL_INITIAL() of that abstract function declaration
116638fd1498Szrj will be later needed to output debug info. */
116738fd1498Szrj if (DECL_ABSTRACT_ORIGIN (decl))
116838fd1498Szrj {
116938fd1498Szrj cgraph_node *origin_node
117038fd1498Szrj = cgraph_node::get_create (DECL_ABSTRACT_ORIGIN (decl));
117138fd1498Szrj origin_node->used_as_abstract_origin = true;
117238fd1498Szrj }
117338fd1498Szrj /* Preserve a functions function context node. It will
117438fd1498Szrj later be needed to output debug info. */
117538fd1498Szrj if (tree fn = decl_function_context (decl))
117638fd1498Szrj {
117738fd1498Szrj cgraph_node *origin_node = cgraph_node::get_create (fn);
117838fd1498Szrj enqueue_node (origin_node);
117938fd1498Szrj }
118038fd1498Szrj }
118138fd1498Szrj else
118238fd1498Szrj {
118338fd1498Szrj varpool_node *vnode = dyn_cast <varpool_node *> (node);
118438fd1498Szrj if (vnode && vnode->definition && !vnode->analyzed)
118538fd1498Szrj vnode->analyze ();
118638fd1498Szrj }
118738fd1498Szrj
118838fd1498Szrj if (node->same_comdat_group)
118938fd1498Szrj {
119038fd1498Szrj symtab_node *next;
119138fd1498Szrj for (next = node->same_comdat_group;
119238fd1498Szrj next != node;
119338fd1498Szrj next = next->same_comdat_group)
119438fd1498Szrj if (!next->comdat_local_p ())
119538fd1498Szrj enqueue_node (next);
119638fd1498Szrj }
119738fd1498Szrj for (i = 0; node->iterate_reference (i, ref); i++)
119838fd1498Szrj if (ref->referred->definition
119938fd1498Szrj && (!DECL_EXTERNAL (ref->referred->decl)
120038fd1498Szrj || ((TREE_CODE (ref->referred->decl) != FUNCTION_DECL
120138fd1498Szrj && optimize)
120238fd1498Szrj || (TREE_CODE (ref->referred->decl) == FUNCTION_DECL
120338fd1498Szrj && opt_for_fn (ref->referred->decl, optimize))
120438fd1498Szrj || node->alias
120538fd1498Szrj || ref->referred->alias)))
120638fd1498Szrj enqueue_node (ref->referred);
120738fd1498Szrj symtab->process_new_functions ();
120838fd1498Szrj }
120938fd1498Szrj }
121038fd1498Szrj update_type_inheritance_graph ();
121138fd1498Szrj
121238fd1498Szrj /* Collect entry points to the unit. */
121338fd1498Szrj if (symtab->dump_file)
121438fd1498Szrj {
121538fd1498Szrj fprintf (symtab->dump_file, "\n\nInitial ");
121638fd1498Szrj symtab->dump (symtab->dump_file);
121738fd1498Szrj }
121838fd1498Szrj
121938fd1498Szrj if (first_time)
122038fd1498Szrj {
122138fd1498Szrj symtab_node *snode;
122238fd1498Szrj FOR_EACH_SYMBOL (snode)
122338fd1498Szrj check_global_declaration (snode);
122438fd1498Szrj }
122538fd1498Szrj
122638fd1498Szrj if (symtab->dump_file)
122738fd1498Szrj fprintf (symtab->dump_file, "\nRemoving unused symbols:");
122838fd1498Szrj
122938fd1498Szrj for (node = symtab->first_symbol ();
123038fd1498Szrj node != first_handled
123138fd1498Szrj && node != first_handled_var; node = next)
123238fd1498Szrj {
123338fd1498Szrj next = node->next;
123438fd1498Szrj if (!node->aux && !node->referred_to_p ())
123538fd1498Szrj {
123638fd1498Szrj if (symtab->dump_file)
123738fd1498Szrj fprintf (symtab->dump_file, " %s", node->name ());
123838fd1498Szrj
123938fd1498Szrj /* See if the debugger can use anything before the DECL
124038fd1498Szrj passes away. Perhaps it can notice a DECL that is now a
124138fd1498Szrj constant and can tag the early DIE with an appropriate
124238fd1498Szrj attribute.
124338fd1498Szrj
124438fd1498Szrj Otherwise, this is the last chance the debug_hooks have
124538fd1498Szrj at looking at optimized away DECLs, since
124638fd1498Szrj late_global_decl will subsequently be called from the
124738fd1498Szrj contents of the now pruned symbol table. */
124838fd1498Szrj if (VAR_P (node->decl)
124938fd1498Szrj && !decl_function_context (node->decl))
125038fd1498Szrj {
125138fd1498Szrj /* We are reclaiming totally unreachable code and variables
125238fd1498Szrj so they effectively appear as readonly. Show that to
125338fd1498Szrj the debug machinery. */
125438fd1498Szrj TREE_READONLY (node->decl) = 1;
125538fd1498Szrj node->definition = false;
125638fd1498Szrj (*debug_hooks->late_global_decl) (node->decl);
125738fd1498Szrj }
125838fd1498Szrj
125938fd1498Szrj node->remove ();
126038fd1498Szrj continue;
126138fd1498Szrj }
126238fd1498Szrj if (cgraph_node *cnode = dyn_cast <cgraph_node *> (node))
126338fd1498Szrj {
126438fd1498Szrj tree decl = node->decl;
126538fd1498Szrj
126638fd1498Szrj if (cnode->definition && !gimple_has_body_p (decl)
126738fd1498Szrj && !cnode->alias
126838fd1498Szrj && !cnode->thunk.thunk_p)
126938fd1498Szrj cnode->reset ();
127038fd1498Szrj
127138fd1498Szrj gcc_assert (!cnode->definition || cnode->thunk.thunk_p
127238fd1498Szrj || cnode->alias
127338fd1498Szrj || gimple_has_body_p (decl)
127438fd1498Szrj || cnode->native_rtl_p ());
127538fd1498Szrj gcc_assert (cnode->analyzed == cnode->definition);
127638fd1498Szrj }
127738fd1498Szrj node->aux = NULL;
127838fd1498Szrj }
127938fd1498Szrj for (;node; node = node->next)
128038fd1498Szrj node->aux = NULL;
128138fd1498Szrj first_analyzed = symtab->first_function ();
128238fd1498Szrj first_analyzed_var = symtab->first_variable ();
128338fd1498Szrj if (symtab->dump_file)
128438fd1498Szrj {
128538fd1498Szrj fprintf (symtab->dump_file, "\n\nReclaimed ");
128638fd1498Szrj symtab->dump (symtab->dump_file);
128738fd1498Szrj }
128838fd1498Szrj bitmap_obstack_release (NULL);
128938fd1498Szrj ggc_collect ();
129038fd1498Szrj /* Initialize assembler name hash, in particular we want to trigger C++
129138fd1498Szrj mangling and same body alias creation before we free DECL_ARGUMENTS
129238fd1498Szrj used by it. */
129338fd1498Szrj if (!seen_error ())
129438fd1498Szrj symtab->symtab_initialize_asm_name_hash ();
129538fd1498Szrj
129638fd1498Szrj input_location = saved_loc;
129738fd1498Szrj }
129838fd1498Szrj
129938fd1498Szrj /* Check declaration of the type of ALIAS for compatibility with its TARGET
130038fd1498Szrj (which may be an ifunc resolver) and issue a diagnostic when they are
130138fd1498Szrj not compatible according to language rules (plus a C++ extension for
130238fd1498Szrj non-static member functions). */
130338fd1498Szrj
130438fd1498Szrj static void
maybe_diag_incompatible_alias(tree alias,tree target)130538fd1498Szrj maybe_diag_incompatible_alias (tree alias, tree target)
130638fd1498Szrj {
130738fd1498Szrj tree altype = TREE_TYPE (alias);
130838fd1498Szrj tree targtype = TREE_TYPE (target);
130938fd1498Szrj
1310*58e805e6Szrj bool ifunc = cgraph_node::get (alias)->ifunc_resolver;
131138fd1498Szrj tree funcptr = altype;
131238fd1498Szrj
131338fd1498Szrj if (ifunc)
131438fd1498Szrj {
131538fd1498Szrj /* Handle attribute ifunc first. */
131638fd1498Szrj if (TREE_CODE (altype) == METHOD_TYPE)
131738fd1498Szrj {
131838fd1498Szrj /* Set FUNCPTR to the type of the alias target. If the type
131938fd1498Szrj is a non-static member function of class C, construct a type
132038fd1498Szrj of an ordinary function taking C* as the first argument,
132138fd1498Szrj followed by the member function argument list, and use it
132238fd1498Szrj instead to check for incompatibility. This conversion is
132338fd1498Szrj not defined by the language but an extension provided by
132438fd1498Szrj G++. */
132538fd1498Szrj
132638fd1498Szrj tree rettype = TREE_TYPE (altype);
132738fd1498Szrj tree args = TYPE_ARG_TYPES (altype);
132838fd1498Szrj altype = build_function_type (rettype, args);
132938fd1498Szrj funcptr = altype;
133038fd1498Szrj }
133138fd1498Szrj
133238fd1498Szrj targtype = TREE_TYPE (targtype);
133338fd1498Szrj
133438fd1498Szrj if (POINTER_TYPE_P (targtype))
133538fd1498Szrj {
133638fd1498Szrj targtype = TREE_TYPE (targtype);
133738fd1498Szrj
133838fd1498Szrj /* Only issue Wattribute-alias for conversions to void* with
133938fd1498Szrj -Wextra. */
134038fd1498Szrj if (VOID_TYPE_P (targtype) && !extra_warnings)
134138fd1498Szrj return;
134238fd1498Szrj
134338fd1498Szrj /* Proceed to handle incompatible ifunc resolvers below. */
134438fd1498Szrj }
134538fd1498Szrj else
134638fd1498Szrj {
134738fd1498Szrj funcptr = build_pointer_type (funcptr);
134838fd1498Szrj
134938fd1498Szrj error_at (DECL_SOURCE_LOCATION (target),
135038fd1498Szrj "%<ifunc%> resolver for %qD must return %qT",
135138fd1498Szrj alias, funcptr);
135238fd1498Szrj inform (DECL_SOURCE_LOCATION (alias),
135338fd1498Szrj "resolver indirect function declared here");
135438fd1498Szrj return;
135538fd1498Szrj }
135638fd1498Szrj }
135738fd1498Szrj
135838fd1498Szrj if ((!FUNC_OR_METHOD_TYPE_P (targtype)
135938fd1498Szrj || (prototype_p (altype)
136038fd1498Szrj && prototype_p (targtype)
136138fd1498Szrj && !types_compatible_p (altype, targtype))))
136238fd1498Szrj {
136338fd1498Szrj /* Warn for incompatibilities. Avoid warning for functions
136438fd1498Szrj without a prototype to make it possible to declare aliases
136538fd1498Szrj without knowing the exact type, as libstdc++ does. */
136638fd1498Szrj if (ifunc)
136738fd1498Szrj {
136838fd1498Szrj funcptr = build_pointer_type (funcptr);
136938fd1498Szrj
137038fd1498Szrj if (warning_at (DECL_SOURCE_LOCATION (target),
137138fd1498Szrj OPT_Wattribute_alias,
137238fd1498Szrj "%<ifunc%> resolver for %qD should return %qT",
137338fd1498Szrj alias, funcptr))
137438fd1498Szrj inform (DECL_SOURCE_LOCATION (alias),
137538fd1498Szrj "resolver indirect function declared here");
137638fd1498Szrj }
137738fd1498Szrj else if (warning_at (DECL_SOURCE_LOCATION (alias),
137838fd1498Szrj OPT_Wattribute_alias,
137938fd1498Szrj "%qD alias between functions of incompatible "
138038fd1498Szrj "types %qT and %qT", alias, altype, targtype))
138138fd1498Szrj inform (DECL_SOURCE_LOCATION (target),
138238fd1498Szrj "aliased declaration here");
138338fd1498Szrj }
138438fd1498Szrj }
138538fd1498Szrj
138638fd1498Szrj /* Translate the ugly representation of aliases as alias pairs into nice
138738fd1498Szrj representation in callgraph. We don't handle all cases yet,
138838fd1498Szrj unfortunately. */
138938fd1498Szrj
139038fd1498Szrj static void
handle_alias_pairs(void)139138fd1498Szrj handle_alias_pairs (void)
139238fd1498Szrj {
139338fd1498Szrj alias_pair *p;
139438fd1498Szrj unsigned i;
139538fd1498Szrj
139638fd1498Szrj for (i = 0; alias_pairs && alias_pairs->iterate (i, &p);)
139738fd1498Szrj {
139838fd1498Szrj symtab_node *target_node = symtab_node::get_for_asmname (p->target);
139938fd1498Szrj
140038fd1498Szrj /* Weakrefs with target not defined in current unit are easy to handle:
140138fd1498Szrj they behave just as external variables except we need to note the
140238fd1498Szrj alias flag to later output the weakref pseudo op into asm file. */
140338fd1498Szrj if (!target_node
140438fd1498Szrj && lookup_attribute ("weakref", DECL_ATTRIBUTES (p->decl)) != NULL)
140538fd1498Szrj {
140638fd1498Szrj symtab_node *node = symtab_node::get (p->decl);
140738fd1498Szrj if (node)
140838fd1498Szrj {
140938fd1498Szrj node->alias_target = p->target;
141038fd1498Szrj node->weakref = true;
141138fd1498Szrj node->alias = true;
141238fd1498Szrj node->transparent_alias = true;
141338fd1498Szrj }
141438fd1498Szrj alias_pairs->unordered_remove (i);
141538fd1498Szrj continue;
141638fd1498Szrj }
141738fd1498Szrj else if (!target_node)
141838fd1498Szrj {
141938fd1498Szrj error ("%q+D aliased to undefined symbol %qE", p->decl, p->target);
142038fd1498Szrj symtab_node *node = symtab_node::get (p->decl);
142138fd1498Szrj if (node)
142238fd1498Szrj node->alias = false;
142338fd1498Szrj alias_pairs->unordered_remove (i);
142438fd1498Szrj continue;
142538fd1498Szrj }
142638fd1498Szrj
142738fd1498Szrj if (DECL_EXTERNAL (target_node->decl)
142838fd1498Szrj /* We use local aliases for C++ thunks to force the tailcall
142938fd1498Szrj to bind locally. This is a hack - to keep it working do
143038fd1498Szrj the following (which is not strictly correct). */
143138fd1498Szrj && (TREE_CODE (target_node->decl) != FUNCTION_DECL
143238fd1498Szrj || ! DECL_VIRTUAL_P (target_node->decl))
143338fd1498Szrj && ! lookup_attribute ("weakref", DECL_ATTRIBUTES (p->decl)))
143438fd1498Szrj {
143538fd1498Szrj error ("%q+D aliased to external symbol %qE",
143638fd1498Szrj p->decl, p->target);
143738fd1498Szrj }
143838fd1498Szrj
143938fd1498Szrj if (TREE_CODE (p->decl) == FUNCTION_DECL
144038fd1498Szrj && target_node && is_a <cgraph_node *> (target_node))
144138fd1498Szrj {
144238fd1498Szrj maybe_diag_incompatible_alias (p->decl, target_node->decl);
144338fd1498Szrj
144438fd1498Szrj cgraph_node *src_node = cgraph_node::get (p->decl);
144538fd1498Szrj if (src_node && src_node->definition)
144638fd1498Szrj src_node->reset ();
144738fd1498Szrj cgraph_node::create_alias (p->decl, target_node->decl);
144838fd1498Szrj alias_pairs->unordered_remove (i);
144938fd1498Szrj }
145038fd1498Szrj else if (VAR_P (p->decl)
145138fd1498Szrj && target_node && is_a <varpool_node *> (target_node))
145238fd1498Szrj {
145338fd1498Szrj varpool_node::create_alias (p->decl, target_node->decl);
145438fd1498Szrj alias_pairs->unordered_remove (i);
145538fd1498Szrj }
145638fd1498Szrj else
145738fd1498Szrj {
145838fd1498Szrj error ("%q+D alias between function and variable is not supported",
145938fd1498Szrj p->decl);
146038fd1498Szrj inform (DECL_SOURCE_LOCATION (target_node->decl),
146138fd1498Szrj "aliased declaration here");
146238fd1498Szrj
146338fd1498Szrj alias_pairs->unordered_remove (i);
146438fd1498Szrj }
146538fd1498Szrj }
146638fd1498Szrj vec_free (alias_pairs);
146738fd1498Szrj }
146838fd1498Szrj
146938fd1498Szrj
147038fd1498Szrj /* Figure out what functions we want to assemble. */
147138fd1498Szrj
147238fd1498Szrj static void
mark_functions_to_output(void)147338fd1498Szrj mark_functions_to_output (void)
147438fd1498Szrj {
147538fd1498Szrj bool check_same_comdat_groups = false;
147638fd1498Szrj cgraph_node *node;
147738fd1498Szrj
147838fd1498Szrj if (flag_checking)
147938fd1498Szrj FOR_EACH_FUNCTION (node)
148038fd1498Szrj gcc_assert (!node->process);
148138fd1498Szrj
148238fd1498Szrj FOR_EACH_FUNCTION (node)
148338fd1498Szrj {
148438fd1498Szrj tree decl = node->decl;
148538fd1498Szrj
148638fd1498Szrj gcc_assert (!node->process || node->same_comdat_group);
148738fd1498Szrj if (node->process)
148838fd1498Szrj continue;
148938fd1498Szrj
149038fd1498Szrj /* We need to output all local functions that are used and not
149138fd1498Szrj always inlined, as well as those that are reachable from
149238fd1498Szrj outside the current compilation unit. */
149338fd1498Szrj if (node->analyzed
149438fd1498Szrj && !node->thunk.thunk_p
149538fd1498Szrj && !node->alias
149638fd1498Szrj && !node->global.inlined_to
149738fd1498Szrj && !TREE_ASM_WRITTEN (decl)
149838fd1498Szrj && !DECL_EXTERNAL (decl))
149938fd1498Szrj {
150038fd1498Szrj node->process = 1;
150138fd1498Szrj if (node->same_comdat_group)
150238fd1498Szrj {
150338fd1498Szrj cgraph_node *next;
150438fd1498Szrj for (next = dyn_cast<cgraph_node *> (node->same_comdat_group);
150538fd1498Szrj next != node;
150638fd1498Szrj next = dyn_cast<cgraph_node *> (next->same_comdat_group))
150738fd1498Szrj if (!next->thunk.thunk_p && !next->alias
150838fd1498Szrj && !next->comdat_local_p ())
150938fd1498Szrj next->process = 1;
151038fd1498Szrj }
151138fd1498Szrj }
151238fd1498Szrj else if (node->same_comdat_group)
151338fd1498Szrj {
151438fd1498Szrj if (flag_checking)
151538fd1498Szrj check_same_comdat_groups = true;
151638fd1498Szrj }
151738fd1498Szrj else
151838fd1498Szrj {
151938fd1498Szrj /* We should've reclaimed all functions that are not needed. */
152038fd1498Szrj if (flag_checking
152138fd1498Szrj && !node->global.inlined_to
152238fd1498Szrj && gimple_has_body_p (decl)
152338fd1498Szrj /* FIXME: in ltrans unit when offline copy is outside partition but inline copies
152438fd1498Szrj are inside partition, we can end up not removing the body since we no longer
152538fd1498Szrj have analyzed node pointing to it. */
152638fd1498Szrj && !node->in_other_partition
152738fd1498Szrj && !node->alias
152838fd1498Szrj && !node->clones
152938fd1498Szrj && !DECL_EXTERNAL (decl))
153038fd1498Szrj {
153138fd1498Szrj node->debug ();
153238fd1498Szrj internal_error ("failed to reclaim unneeded function");
153338fd1498Szrj }
153438fd1498Szrj gcc_assert (node->global.inlined_to
153538fd1498Szrj || !gimple_has_body_p (decl)
153638fd1498Szrj || node->in_other_partition
153738fd1498Szrj || node->clones
153838fd1498Szrj || DECL_ARTIFICIAL (decl)
153938fd1498Szrj || DECL_EXTERNAL (decl));
154038fd1498Szrj
154138fd1498Szrj }
154238fd1498Szrj
154338fd1498Szrj }
154438fd1498Szrj if (flag_checking && check_same_comdat_groups)
154538fd1498Szrj FOR_EACH_FUNCTION (node)
154638fd1498Szrj if (node->same_comdat_group && !node->process)
154738fd1498Szrj {
154838fd1498Szrj tree decl = node->decl;
154938fd1498Szrj if (!node->global.inlined_to
155038fd1498Szrj && gimple_has_body_p (decl)
155138fd1498Szrj /* FIXME: in an ltrans unit when the offline copy is outside a
155238fd1498Szrj partition but inline copies are inside a partition, we can
155338fd1498Szrj end up not removing the body since we no longer have an
155438fd1498Szrj analyzed node pointing to it. */
155538fd1498Szrj && !node->in_other_partition
155638fd1498Szrj && !node->clones
155738fd1498Szrj && !DECL_EXTERNAL (decl))
155838fd1498Szrj {
155938fd1498Szrj node->debug ();
156038fd1498Szrj internal_error ("failed to reclaim unneeded function in same "
156138fd1498Szrj "comdat group");
156238fd1498Szrj }
156338fd1498Szrj }
156438fd1498Szrj }
156538fd1498Szrj
156638fd1498Szrj /* DECL is FUNCTION_DECL. Initialize datastructures so DECL is a function
156738fd1498Szrj in lowered gimple form. IN_SSA is true if the gimple is in SSA.
156838fd1498Szrj
156938fd1498Szrj Set current_function_decl and cfun to newly constructed empty function body.
157038fd1498Szrj return basic block in the function body. */
157138fd1498Szrj
157238fd1498Szrj basic_block
init_lowered_empty_function(tree decl,bool in_ssa,profile_count count)157338fd1498Szrj init_lowered_empty_function (tree decl, bool in_ssa, profile_count count)
157438fd1498Szrj {
157538fd1498Szrj basic_block bb;
157638fd1498Szrj edge e;
157738fd1498Szrj
157838fd1498Szrj current_function_decl = decl;
157938fd1498Szrj allocate_struct_function (decl, false);
158038fd1498Szrj gimple_register_cfg_hooks ();
158138fd1498Szrj init_empty_tree_cfg ();
158238fd1498Szrj init_tree_ssa (cfun);
158338fd1498Szrj
158438fd1498Szrj if (in_ssa)
158538fd1498Szrj {
158638fd1498Szrj init_ssa_operands (cfun);
158738fd1498Szrj cfun->gimple_df->in_ssa_p = true;
158838fd1498Szrj cfun->curr_properties |= PROP_ssa;
158938fd1498Szrj }
159038fd1498Szrj
159138fd1498Szrj DECL_INITIAL (decl) = make_node (BLOCK);
159238fd1498Szrj BLOCK_SUPERCONTEXT (DECL_INITIAL (decl)) = decl;
159338fd1498Szrj
159438fd1498Szrj DECL_SAVED_TREE (decl) = error_mark_node;
159538fd1498Szrj cfun->curr_properties |= (PROP_gimple_lcf | PROP_gimple_leh | PROP_gimple_any
159638fd1498Szrj | PROP_cfg | PROP_loops);
159738fd1498Szrj
159838fd1498Szrj set_loops_for_fn (cfun, ggc_cleared_alloc<loops> ());
159938fd1498Szrj init_loops_structure (cfun, loops_for_fn (cfun), 1);
160038fd1498Szrj loops_for_fn (cfun)->state |= LOOPS_MAY_HAVE_MULTIPLE_LATCHES;
160138fd1498Szrj
160238fd1498Szrj /* Create BB for body of the function and connect it properly. */
160338fd1498Szrj ENTRY_BLOCK_PTR_FOR_FN (cfun)->count = count;
160438fd1498Szrj EXIT_BLOCK_PTR_FOR_FN (cfun)->count = count;
160538fd1498Szrj bb = create_basic_block (NULL, ENTRY_BLOCK_PTR_FOR_FN (cfun));
160638fd1498Szrj bb->count = count;
160738fd1498Szrj e = make_edge (ENTRY_BLOCK_PTR_FOR_FN (cfun), bb, EDGE_FALLTHRU);
160838fd1498Szrj e->probability = profile_probability::always ();
160938fd1498Szrj e = make_edge (bb, EXIT_BLOCK_PTR_FOR_FN (cfun), 0);
161038fd1498Szrj e->probability = profile_probability::always ();
161138fd1498Szrj add_bb_to_loop (bb, ENTRY_BLOCK_PTR_FOR_FN (cfun)->loop_father);
161238fd1498Szrj
161338fd1498Szrj return bb;
161438fd1498Szrj }
161538fd1498Szrj
161638fd1498Szrj /* Adjust PTR by the constant FIXED_OFFSET, and by the vtable
161738fd1498Szrj offset indicated by VIRTUAL_OFFSET, if that is
161838fd1498Szrj non-null. THIS_ADJUSTING is nonzero for a this adjusting thunk and
161938fd1498Szrj zero for a result adjusting thunk. */
162038fd1498Szrj
162138fd1498Szrj tree
thunk_adjust(gimple_stmt_iterator * bsi,tree ptr,bool this_adjusting,HOST_WIDE_INT fixed_offset,tree virtual_offset)162238fd1498Szrj thunk_adjust (gimple_stmt_iterator * bsi,
162338fd1498Szrj tree ptr, bool this_adjusting,
162438fd1498Szrj HOST_WIDE_INT fixed_offset, tree virtual_offset)
162538fd1498Szrj {
162638fd1498Szrj gassign *stmt;
162738fd1498Szrj tree ret;
162838fd1498Szrj
162938fd1498Szrj if (this_adjusting
163038fd1498Szrj && fixed_offset != 0)
163138fd1498Szrj {
163238fd1498Szrj stmt = gimple_build_assign
163338fd1498Szrj (ptr, fold_build_pointer_plus_hwi_loc (input_location,
163438fd1498Szrj ptr,
163538fd1498Szrj fixed_offset));
163638fd1498Szrj gsi_insert_after (bsi, stmt, GSI_NEW_STMT);
163738fd1498Szrj }
163838fd1498Szrj
163938fd1498Szrj /* If there's a virtual offset, look up that value in the vtable and
164038fd1498Szrj adjust the pointer again. */
164138fd1498Szrj if (virtual_offset)
164238fd1498Szrj {
164338fd1498Szrj tree vtabletmp;
164438fd1498Szrj tree vtabletmp2;
164538fd1498Szrj tree vtabletmp3;
164638fd1498Szrj
164738fd1498Szrj if (!vtable_entry_type)
164838fd1498Szrj {
164938fd1498Szrj tree vfunc_type = make_node (FUNCTION_TYPE);
165038fd1498Szrj TREE_TYPE (vfunc_type) = integer_type_node;
165138fd1498Szrj TYPE_ARG_TYPES (vfunc_type) = NULL_TREE;
165238fd1498Szrj layout_type (vfunc_type);
165338fd1498Szrj
165438fd1498Szrj vtable_entry_type = build_pointer_type (vfunc_type);
165538fd1498Szrj }
165638fd1498Szrj
165738fd1498Szrj vtabletmp =
165838fd1498Szrj create_tmp_reg (build_pointer_type
165938fd1498Szrj (build_pointer_type (vtable_entry_type)), "vptr");
166038fd1498Szrj
166138fd1498Szrj /* The vptr is always at offset zero in the object. */
166238fd1498Szrj stmt = gimple_build_assign (vtabletmp,
166338fd1498Szrj build1 (NOP_EXPR, TREE_TYPE (vtabletmp),
166438fd1498Szrj ptr));
166538fd1498Szrj gsi_insert_after (bsi, stmt, GSI_NEW_STMT);
166638fd1498Szrj
166738fd1498Szrj /* Form the vtable address. */
166838fd1498Szrj vtabletmp2 = create_tmp_reg (TREE_TYPE (TREE_TYPE (vtabletmp)),
166938fd1498Szrj "vtableaddr");
167038fd1498Szrj stmt = gimple_build_assign (vtabletmp2,
167138fd1498Szrj build_simple_mem_ref (vtabletmp));
167238fd1498Szrj gsi_insert_after (bsi, stmt, GSI_NEW_STMT);
167338fd1498Szrj
167438fd1498Szrj /* Find the entry with the vcall offset. */
167538fd1498Szrj stmt = gimple_build_assign (vtabletmp2,
167638fd1498Szrj fold_build_pointer_plus_loc (input_location,
167738fd1498Szrj vtabletmp2,
167838fd1498Szrj virtual_offset));
167938fd1498Szrj gsi_insert_after (bsi, stmt, GSI_NEW_STMT);
168038fd1498Szrj
168138fd1498Szrj /* Get the offset itself. */
168238fd1498Szrj vtabletmp3 = create_tmp_reg (TREE_TYPE (TREE_TYPE (vtabletmp2)),
168338fd1498Szrj "vcalloffset");
168438fd1498Szrj stmt = gimple_build_assign (vtabletmp3,
168538fd1498Szrj build_simple_mem_ref (vtabletmp2));
168638fd1498Szrj gsi_insert_after (bsi, stmt, GSI_NEW_STMT);
168738fd1498Szrj
168838fd1498Szrj /* Adjust the `this' pointer. */
168938fd1498Szrj ptr = fold_build_pointer_plus_loc (input_location, ptr, vtabletmp3);
169038fd1498Szrj ptr = force_gimple_operand_gsi (bsi, ptr, true, NULL_TREE, false,
169138fd1498Szrj GSI_CONTINUE_LINKING);
169238fd1498Szrj }
169338fd1498Szrj
169438fd1498Szrj if (!this_adjusting
169538fd1498Szrj && fixed_offset != 0)
169638fd1498Szrj /* Adjust the pointer by the constant. */
169738fd1498Szrj {
169838fd1498Szrj tree ptrtmp;
169938fd1498Szrj
170038fd1498Szrj if (VAR_P (ptr))
170138fd1498Szrj ptrtmp = ptr;
170238fd1498Szrj else
170338fd1498Szrj {
170438fd1498Szrj ptrtmp = create_tmp_reg (TREE_TYPE (ptr), "ptr");
170538fd1498Szrj stmt = gimple_build_assign (ptrtmp, ptr);
170638fd1498Szrj gsi_insert_after (bsi, stmt, GSI_NEW_STMT);
170738fd1498Szrj }
170838fd1498Szrj ptr = fold_build_pointer_plus_hwi_loc (input_location,
170938fd1498Szrj ptrtmp, fixed_offset);
171038fd1498Szrj }
171138fd1498Szrj
171238fd1498Szrj /* Emit the statement and gimplify the adjustment expression. */
171338fd1498Szrj ret = create_tmp_reg (TREE_TYPE (ptr), "adjusted_this");
171438fd1498Szrj stmt = gimple_build_assign (ret, ptr);
171538fd1498Szrj gsi_insert_after (bsi, stmt, GSI_NEW_STMT);
171638fd1498Szrj
171738fd1498Szrj return ret;
171838fd1498Szrj }
171938fd1498Szrj
172038fd1498Szrj /* Expand thunk NODE to gimple if possible.
172138fd1498Szrj When FORCE_GIMPLE_THUNK is true, gimple thunk is created and
172238fd1498Szrj no assembler is produced.
172338fd1498Szrj When OUTPUT_ASM_THUNK is true, also produce assembler for
172438fd1498Szrj thunks that are not lowered. */
172538fd1498Szrj
172638fd1498Szrj bool
expand_thunk(bool output_asm_thunks,bool force_gimple_thunk)172738fd1498Szrj cgraph_node::expand_thunk (bool output_asm_thunks, bool force_gimple_thunk)
172838fd1498Szrj {
172938fd1498Szrj bool this_adjusting = thunk.this_adjusting;
173038fd1498Szrj HOST_WIDE_INT fixed_offset = thunk.fixed_offset;
173138fd1498Szrj HOST_WIDE_INT virtual_value = thunk.virtual_value;
173238fd1498Szrj tree virtual_offset = NULL;
173338fd1498Szrj tree alias = callees->callee->decl;
173438fd1498Szrj tree thunk_fndecl = decl;
173538fd1498Szrj tree a;
173638fd1498Szrj
173738fd1498Szrj /* Instrumentation thunk is the same function with
173838fd1498Szrj a different signature. Never need to expand it. */
173938fd1498Szrj if (thunk.add_pointer_bounds_args)
174038fd1498Szrj return false;
174138fd1498Szrj
174238fd1498Szrj if (!force_gimple_thunk && this_adjusting
174338fd1498Szrj && targetm.asm_out.can_output_mi_thunk (thunk_fndecl, fixed_offset,
174438fd1498Szrj virtual_value, alias))
174538fd1498Szrj {
174638fd1498Szrj const char *fnname;
174738fd1498Szrj tree fn_block;
174838fd1498Szrj tree restype = TREE_TYPE (TREE_TYPE (thunk_fndecl));
174938fd1498Szrj
175038fd1498Szrj if (!output_asm_thunks)
175138fd1498Szrj {
175238fd1498Szrj analyzed = true;
175338fd1498Szrj return false;
175438fd1498Szrj }
175538fd1498Szrj
175638fd1498Szrj if (in_lto_p)
175738fd1498Szrj get_untransformed_body ();
175838fd1498Szrj a = DECL_ARGUMENTS (thunk_fndecl);
175938fd1498Szrj
176038fd1498Szrj current_function_decl = thunk_fndecl;
176138fd1498Szrj
176238fd1498Szrj /* Ensure thunks are emitted in their correct sections. */
176338fd1498Szrj resolve_unique_section (thunk_fndecl, 0,
176438fd1498Szrj flag_function_sections);
176538fd1498Szrj
176638fd1498Szrj DECL_RESULT (thunk_fndecl)
176738fd1498Szrj = build_decl (DECL_SOURCE_LOCATION (thunk_fndecl),
176838fd1498Szrj RESULT_DECL, 0, restype);
176938fd1498Szrj DECL_CONTEXT (DECL_RESULT (thunk_fndecl)) = thunk_fndecl;
177038fd1498Szrj fnname = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (thunk_fndecl));
177138fd1498Szrj
177238fd1498Szrj /* The back end expects DECL_INITIAL to contain a BLOCK, so we
177338fd1498Szrj create one. */
177438fd1498Szrj fn_block = make_node (BLOCK);
177538fd1498Szrj BLOCK_VARS (fn_block) = a;
177638fd1498Szrj DECL_INITIAL (thunk_fndecl) = fn_block;
177738fd1498Szrj BLOCK_SUPERCONTEXT (fn_block) = thunk_fndecl;
177838fd1498Szrj allocate_struct_function (thunk_fndecl, false);
177938fd1498Szrj init_function_start (thunk_fndecl);
178038fd1498Szrj cfun->is_thunk = 1;
178138fd1498Szrj insn_locations_init ();
178238fd1498Szrj set_curr_insn_location (DECL_SOURCE_LOCATION (thunk_fndecl));
178338fd1498Szrj prologue_location = curr_insn_location ();
178438fd1498Szrj assemble_start_function (thunk_fndecl, fnname);
178538fd1498Szrj
178638fd1498Szrj targetm.asm_out.output_mi_thunk (asm_out_file, thunk_fndecl,
178738fd1498Szrj fixed_offset, virtual_value, alias);
178838fd1498Szrj
178938fd1498Szrj assemble_end_function (thunk_fndecl, fnname);
179038fd1498Szrj insn_locations_finalize ();
179138fd1498Szrj init_insn_lengths ();
179238fd1498Szrj free_after_compilation (cfun);
179338fd1498Szrj TREE_ASM_WRITTEN (thunk_fndecl) = 1;
179438fd1498Szrj thunk.thunk_p = false;
179538fd1498Szrj analyzed = false;
179638fd1498Szrj }
179738fd1498Szrj else if (stdarg_p (TREE_TYPE (thunk_fndecl)))
179838fd1498Szrj {
179938fd1498Szrj error ("generic thunk code fails for method %qD which uses %<...%>",
180038fd1498Szrj thunk_fndecl);
180138fd1498Szrj TREE_ASM_WRITTEN (thunk_fndecl) = 1;
180238fd1498Szrj analyzed = true;
180338fd1498Szrj return false;
180438fd1498Szrj }
180538fd1498Szrj else
180638fd1498Szrj {
180738fd1498Szrj tree restype;
180838fd1498Szrj basic_block bb, then_bb, else_bb, return_bb;
180938fd1498Szrj gimple_stmt_iterator bsi;
181038fd1498Szrj int nargs = 0;
181138fd1498Szrj tree arg;
181238fd1498Szrj int i;
181338fd1498Szrj tree resdecl;
181438fd1498Szrj tree restmp = NULL;
181538fd1498Szrj tree resbnd = NULL;
181638fd1498Szrj
181738fd1498Szrj gcall *call;
181838fd1498Szrj greturn *ret;
181938fd1498Szrj bool alias_is_noreturn = TREE_THIS_VOLATILE (alias);
182038fd1498Szrj
182138fd1498Szrj /* We may be called from expand_thunk that releses body except for
182238fd1498Szrj DECL_ARGUMENTS. In this case force_gimple_thunk is true. */
182338fd1498Szrj if (in_lto_p && !force_gimple_thunk)
182438fd1498Szrj get_untransformed_body ();
182538fd1498Szrj a = DECL_ARGUMENTS (thunk_fndecl);
182638fd1498Szrj
182738fd1498Szrj current_function_decl = thunk_fndecl;
182838fd1498Szrj
182938fd1498Szrj /* Ensure thunks are emitted in their correct sections. */
183038fd1498Szrj resolve_unique_section (thunk_fndecl, 0,
183138fd1498Szrj flag_function_sections);
183238fd1498Szrj
183338fd1498Szrj DECL_IGNORED_P (thunk_fndecl) = 1;
183438fd1498Szrj bitmap_obstack_initialize (NULL);
183538fd1498Szrj
183638fd1498Szrj if (thunk.virtual_offset_p)
183738fd1498Szrj virtual_offset = size_int (virtual_value);
183838fd1498Szrj
183938fd1498Szrj /* Build the return declaration for the function. */
184038fd1498Szrj restype = TREE_TYPE (TREE_TYPE (thunk_fndecl));
184138fd1498Szrj if (DECL_RESULT (thunk_fndecl) == NULL_TREE)
184238fd1498Szrj {
184338fd1498Szrj resdecl = build_decl (input_location, RESULT_DECL, 0, restype);
184438fd1498Szrj DECL_ARTIFICIAL (resdecl) = 1;
184538fd1498Szrj DECL_IGNORED_P (resdecl) = 1;
184638fd1498Szrj DECL_RESULT (thunk_fndecl) = resdecl;
184738fd1498Szrj DECL_CONTEXT (DECL_RESULT (thunk_fndecl)) = thunk_fndecl;
184838fd1498Szrj }
184938fd1498Szrj else
185038fd1498Szrj resdecl = DECL_RESULT (thunk_fndecl);
185138fd1498Szrj
185238fd1498Szrj profile_count cfg_count = count;
185338fd1498Szrj if (!cfg_count.initialized_p ())
185438fd1498Szrj cfg_count = profile_count::from_gcov_type (BB_FREQ_MAX).guessed_local ();
185538fd1498Szrj
185638fd1498Szrj bb = then_bb = else_bb = return_bb
185738fd1498Szrj = init_lowered_empty_function (thunk_fndecl, true, cfg_count);
185838fd1498Szrj
185938fd1498Szrj bsi = gsi_start_bb (bb);
186038fd1498Szrj
186138fd1498Szrj /* Build call to the function being thunked. */
186238fd1498Szrj if (!VOID_TYPE_P (restype)
186338fd1498Szrj && (!alias_is_noreturn
186438fd1498Szrj || TREE_ADDRESSABLE (restype)
186538fd1498Szrj || TREE_CODE (TYPE_SIZE_UNIT (restype)) != INTEGER_CST))
186638fd1498Szrj {
186738fd1498Szrj if (DECL_BY_REFERENCE (resdecl))
186838fd1498Szrj {
186938fd1498Szrj restmp = gimple_fold_indirect_ref (resdecl);
187038fd1498Szrj if (!restmp)
187138fd1498Szrj restmp = build2 (MEM_REF,
187238fd1498Szrj TREE_TYPE (TREE_TYPE (DECL_RESULT (alias))),
187338fd1498Szrj resdecl,
187438fd1498Szrj build_int_cst (TREE_TYPE
187538fd1498Szrj (DECL_RESULT (alias)), 0));
187638fd1498Szrj }
187738fd1498Szrj else if (!is_gimple_reg_type (restype))
187838fd1498Szrj {
187938fd1498Szrj if (aggregate_value_p (resdecl, TREE_TYPE (thunk_fndecl)))
188038fd1498Szrj {
188138fd1498Szrj restmp = resdecl;
188238fd1498Szrj
188338fd1498Szrj if (VAR_P (restmp))
188438fd1498Szrj add_local_decl (cfun, restmp);
188538fd1498Szrj BLOCK_VARS (DECL_INITIAL (current_function_decl)) = restmp;
188638fd1498Szrj }
188738fd1498Szrj else
188838fd1498Szrj restmp = create_tmp_var (restype, "retval");
188938fd1498Szrj }
189038fd1498Szrj else
189138fd1498Szrj restmp = create_tmp_reg (restype, "retval");
189238fd1498Szrj }
189338fd1498Szrj
189438fd1498Szrj for (arg = a; arg; arg = DECL_CHAIN (arg))
189538fd1498Szrj nargs++;
189638fd1498Szrj auto_vec<tree> vargs (nargs);
189738fd1498Szrj i = 0;
189838fd1498Szrj arg = a;
189938fd1498Szrj if (this_adjusting)
190038fd1498Szrj {
190138fd1498Szrj vargs.quick_push (thunk_adjust (&bsi, a, 1, fixed_offset,
190238fd1498Szrj virtual_offset));
190338fd1498Szrj arg = DECL_CHAIN (a);
190438fd1498Szrj i = 1;
190538fd1498Szrj }
190638fd1498Szrj
190738fd1498Szrj if (nargs)
190838fd1498Szrj for (; i < nargs; i++, arg = DECL_CHAIN (arg))
190938fd1498Szrj {
191038fd1498Szrj tree tmp = arg;
191138fd1498Szrj if (VECTOR_TYPE_P (TREE_TYPE (arg))
191238fd1498Szrj || TREE_CODE (TREE_TYPE (arg)) == COMPLEX_TYPE)
191338fd1498Szrj DECL_GIMPLE_REG_P (arg) = 1;
191438fd1498Szrj
191538fd1498Szrj if (!is_gimple_val (arg))
191638fd1498Szrj {
191738fd1498Szrj tmp = create_tmp_reg (TYPE_MAIN_VARIANT
191838fd1498Szrj (TREE_TYPE (arg)), "arg");
191938fd1498Szrj gimple *stmt = gimple_build_assign (tmp, arg);
192038fd1498Szrj gsi_insert_after (&bsi, stmt, GSI_NEW_STMT);
192138fd1498Szrj }
192238fd1498Szrj vargs.quick_push (tmp);
192338fd1498Szrj }
192438fd1498Szrj call = gimple_build_call_vec (build_fold_addr_expr_loc (0, alias), vargs);
192538fd1498Szrj callees->call_stmt = call;
192638fd1498Szrj gimple_call_set_from_thunk (call, true);
192738fd1498Szrj gimple_call_set_with_bounds (call, instrumentation_clone);
192838fd1498Szrj
192938fd1498Szrj /* Return slot optimization is always possible and in fact requred to
193038fd1498Szrj return values with DECL_BY_REFERENCE. */
193138fd1498Szrj if (aggregate_value_p (resdecl, TREE_TYPE (thunk_fndecl))
193238fd1498Szrj && (!is_gimple_reg_type (TREE_TYPE (resdecl))
193338fd1498Szrj || DECL_BY_REFERENCE (resdecl)))
193438fd1498Szrj gimple_call_set_return_slot_opt (call, true);
193538fd1498Szrj
193638fd1498Szrj if (restmp)
193738fd1498Szrj {
193838fd1498Szrj gimple_call_set_lhs (call, restmp);
193938fd1498Szrj gcc_assert (useless_type_conversion_p (TREE_TYPE (restmp),
194038fd1498Szrj TREE_TYPE (TREE_TYPE (alias))));
194138fd1498Szrj }
194238fd1498Szrj gsi_insert_after (&bsi, call, GSI_NEW_STMT);
194338fd1498Szrj if (!alias_is_noreturn)
194438fd1498Szrj {
194538fd1498Szrj if (instrumentation_clone
194638fd1498Szrj && !DECL_BY_REFERENCE (resdecl)
194738fd1498Szrj && restmp
194838fd1498Szrj && BOUNDED_P (restmp))
194938fd1498Szrj {
195038fd1498Szrj resbnd = chkp_insert_retbnd_call (NULL, restmp, &bsi);
195138fd1498Szrj create_edge (get_create (gimple_call_fndecl (gsi_stmt (bsi))),
195238fd1498Szrj as_a <gcall *> (gsi_stmt (bsi)),
195338fd1498Szrj callees->count);
195438fd1498Szrj }
195538fd1498Szrj
195638fd1498Szrj if (restmp && !this_adjusting
195738fd1498Szrj && (fixed_offset || virtual_offset))
195838fd1498Szrj {
195938fd1498Szrj tree true_label = NULL_TREE;
196038fd1498Szrj
196138fd1498Szrj if (TREE_CODE (TREE_TYPE (restmp)) == POINTER_TYPE)
196238fd1498Szrj {
196338fd1498Szrj gimple *stmt;
196438fd1498Szrj edge e;
196538fd1498Szrj /* If the return type is a pointer, we need to
196638fd1498Szrj protect against NULL. We know there will be an
196738fd1498Szrj adjustment, because that's why we're emitting a
196838fd1498Szrj thunk. */
196938fd1498Szrj then_bb = create_basic_block (NULL, bb);
197038fd1498Szrj then_bb->count = cfg_count - cfg_count.apply_scale (1, 16);
197138fd1498Szrj return_bb = create_basic_block (NULL, then_bb);
197238fd1498Szrj return_bb->count = cfg_count;
197338fd1498Szrj else_bb = create_basic_block (NULL, else_bb);
197438fd1498Szrj else_bb->count = cfg_count.apply_scale (1, 16);
197538fd1498Szrj add_bb_to_loop (then_bb, bb->loop_father);
197638fd1498Szrj add_bb_to_loop (return_bb, bb->loop_father);
197738fd1498Szrj add_bb_to_loop (else_bb, bb->loop_father);
197838fd1498Szrj remove_edge (single_succ_edge (bb));
197938fd1498Szrj true_label = gimple_block_label (then_bb);
198038fd1498Szrj stmt = gimple_build_cond (NE_EXPR, restmp,
198138fd1498Szrj build_zero_cst (TREE_TYPE (restmp)),
198238fd1498Szrj NULL_TREE, NULL_TREE);
198338fd1498Szrj gsi_insert_after (&bsi, stmt, GSI_NEW_STMT);
198438fd1498Szrj e = make_edge (bb, then_bb, EDGE_TRUE_VALUE);
198538fd1498Szrj e->probability = profile_probability::guessed_always ()
198638fd1498Szrj .apply_scale (1, 16);
198738fd1498Szrj e = make_edge (bb, else_bb, EDGE_FALSE_VALUE);
198838fd1498Szrj e->probability = profile_probability::guessed_always ()
198938fd1498Szrj .apply_scale (1, 16);
199038fd1498Szrj make_single_succ_edge (return_bb,
199138fd1498Szrj EXIT_BLOCK_PTR_FOR_FN (cfun), 0);
199238fd1498Szrj make_single_succ_edge (then_bb, return_bb, EDGE_FALLTHRU);
199338fd1498Szrj e = make_edge (else_bb, return_bb, EDGE_FALLTHRU);
199438fd1498Szrj e->probability = profile_probability::always ();
199538fd1498Szrj bsi = gsi_last_bb (then_bb);
199638fd1498Szrj }
199738fd1498Szrj
199838fd1498Szrj restmp = thunk_adjust (&bsi, restmp, /*this_adjusting=*/0,
199938fd1498Szrj fixed_offset, virtual_offset);
200038fd1498Szrj if (true_label)
200138fd1498Szrj {
200238fd1498Szrj gimple *stmt;
200338fd1498Szrj bsi = gsi_last_bb (else_bb);
200438fd1498Szrj stmt = gimple_build_assign (restmp,
200538fd1498Szrj build_zero_cst (TREE_TYPE (restmp)));
200638fd1498Szrj gsi_insert_after (&bsi, stmt, GSI_NEW_STMT);
200738fd1498Szrj bsi = gsi_last_bb (return_bb);
200838fd1498Szrj }
200938fd1498Szrj }
201038fd1498Szrj else
201138fd1498Szrj gimple_call_set_tail (call, true);
201238fd1498Szrj
201338fd1498Szrj /* Build return value. */
201438fd1498Szrj if (!DECL_BY_REFERENCE (resdecl))
201538fd1498Szrj ret = gimple_build_return (restmp);
201638fd1498Szrj else
201738fd1498Szrj ret = gimple_build_return (resdecl);
201838fd1498Szrj gimple_return_set_retbnd (ret, resbnd);
201938fd1498Szrj
202038fd1498Szrj gsi_insert_after (&bsi, ret, GSI_NEW_STMT);
202138fd1498Szrj }
202238fd1498Szrj else
202338fd1498Szrj {
202438fd1498Szrj gimple_call_set_tail (call, true);
202538fd1498Szrj remove_edge (single_succ_edge (bb));
202638fd1498Szrj }
202738fd1498Szrj
202838fd1498Szrj cfun->gimple_df->in_ssa_p = true;
202938fd1498Szrj update_max_bb_count ();
203038fd1498Szrj profile_status_for_fn (cfun)
203138fd1498Szrj = cfg_count.initialized_p () && cfg_count.ipa_p ()
203238fd1498Szrj ? PROFILE_READ : PROFILE_GUESSED;
203338fd1498Szrj /* FIXME: C++ FE should stop setting TREE_ASM_WRITTEN on thunks. */
203438fd1498Szrj TREE_ASM_WRITTEN (thunk_fndecl) = false;
203538fd1498Szrj delete_unreachable_blocks ();
203638fd1498Szrj update_ssa (TODO_update_ssa);
203738fd1498Szrj checking_verify_flow_info ();
203838fd1498Szrj free_dominance_info (CDI_DOMINATORS);
203938fd1498Szrj
204038fd1498Szrj /* Since we want to emit the thunk, we explicitly mark its name as
204138fd1498Szrj referenced. */
204238fd1498Szrj thunk.thunk_p = false;
204338fd1498Szrj lowered = true;
204438fd1498Szrj bitmap_obstack_release (NULL);
204538fd1498Szrj }
204638fd1498Szrj current_function_decl = NULL;
204738fd1498Szrj set_cfun (NULL);
204838fd1498Szrj return true;
204938fd1498Szrj }
205038fd1498Szrj
205138fd1498Szrj /* Assemble thunks and aliases associated to node. */
205238fd1498Szrj
205338fd1498Szrj void
assemble_thunks_and_aliases(void)205438fd1498Szrj cgraph_node::assemble_thunks_and_aliases (void)
205538fd1498Szrj {
205638fd1498Szrj cgraph_edge *e;
205738fd1498Szrj ipa_ref *ref;
205838fd1498Szrj
205938fd1498Szrj for (e = callers; e;)
206038fd1498Szrj if (e->caller->thunk.thunk_p
206138fd1498Szrj && !e->caller->global.inlined_to
206238fd1498Szrj && !e->caller->thunk.add_pointer_bounds_args)
206338fd1498Szrj {
206438fd1498Szrj cgraph_node *thunk = e->caller;
206538fd1498Szrj
206638fd1498Szrj e = e->next_caller;
206738fd1498Szrj thunk->expand_thunk (true, false);
206838fd1498Szrj thunk->assemble_thunks_and_aliases ();
206938fd1498Szrj }
207038fd1498Szrj else
207138fd1498Szrj e = e->next_caller;
207238fd1498Szrj
207338fd1498Szrj FOR_EACH_ALIAS (this, ref)
207438fd1498Szrj {
207538fd1498Szrj cgraph_node *alias = dyn_cast <cgraph_node *> (ref->referring);
207638fd1498Szrj if (!alias->transparent_alias)
207738fd1498Szrj {
207838fd1498Szrj bool saved_written = TREE_ASM_WRITTEN (decl);
207938fd1498Szrj
208038fd1498Szrj /* Force assemble_alias to really output the alias this time instead
208138fd1498Szrj of buffering it in same alias pairs. */
208238fd1498Szrj TREE_ASM_WRITTEN (decl) = 1;
208338fd1498Szrj do_assemble_alias (alias->decl,
208438fd1498Szrj DECL_ASSEMBLER_NAME (decl));
208538fd1498Szrj alias->assemble_thunks_and_aliases ();
208638fd1498Szrj TREE_ASM_WRITTEN (decl) = saved_written;
208738fd1498Szrj }
208838fd1498Szrj }
208938fd1498Szrj }
209038fd1498Szrj
209138fd1498Szrj /* Expand function specified by node. */
209238fd1498Szrj
209338fd1498Szrj void
expand(void)209438fd1498Szrj cgraph_node::expand (void)
209538fd1498Szrj {
209638fd1498Szrj location_t saved_loc;
209738fd1498Szrj
209838fd1498Szrj /* We ought to not compile any inline clones. */
209938fd1498Szrj gcc_assert (!global.inlined_to);
210038fd1498Szrj
210138fd1498Szrj /* __RTL functions are compiled as soon as they are parsed, so don't
210238fd1498Szrj do it again. */
210338fd1498Szrj if (native_rtl_p ())
210438fd1498Szrj return;
210538fd1498Szrj
210638fd1498Szrj announce_function (decl);
210738fd1498Szrj process = 0;
210838fd1498Szrj gcc_assert (lowered);
210938fd1498Szrj get_untransformed_body ();
211038fd1498Szrj
211138fd1498Szrj /* Generate RTL for the body of DECL. */
211238fd1498Szrj
211338fd1498Szrj timevar_push (TV_REST_OF_COMPILATION);
211438fd1498Szrj
211538fd1498Szrj gcc_assert (symtab->global_info_ready);
211638fd1498Szrj
211738fd1498Szrj /* Initialize the default bitmap obstack. */
211838fd1498Szrj bitmap_obstack_initialize (NULL);
211938fd1498Szrj
212038fd1498Szrj /* Initialize the RTL code for the function. */
212138fd1498Szrj saved_loc = input_location;
212238fd1498Szrj input_location = DECL_SOURCE_LOCATION (decl);
212338fd1498Szrj
212438fd1498Szrj gcc_assert (DECL_STRUCT_FUNCTION (decl));
212538fd1498Szrj push_cfun (DECL_STRUCT_FUNCTION (decl));
212638fd1498Szrj init_function_start (decl);
212738fd1498Szrj
212838fd1498Szrj gimple_register_cfg_hooks ();
212938fd1498Szrj
213038fd1498Szrj bitmap_obstack_initialize (®_obstack); /* FIXME, only at RTL generation*/
213138fd1498Szrj
213238fd1498Szrj execute_all_ipa_transforms ();
213338fd1498Szrj
213438fd1498Szrj /* Perform all tree transforms and optimizations. */
213538fd1498Szrj
213638fd1498Szrj /* Signal the start of passes. */
213738fd1498Szrj invoke_plugin_callbacks (PLUGIN_ALL_PASSES_START, NULL);
213838fd1498Szrj
213938fd1498Szrj execute_pass_list (cfun, g->get_passes ()->all_passes);
214038fd1498Szrj
214138fd1498Szrj /* Signal the end of passes. */
214238fd1498Szrj invoke_plugin_callbacks (PLUGIN_ALL_PASSES_END, NULL);
214338fd1498Szrj
214438fd1498Szrj bitmap_obstack_release (®_obstack);
214538fd1498Szrj
214638fd1498Szrj /* Release the default bitmap obstack. */
214738fd1498Szrj bitmap_obstack_release (NULL);
214838fd1498Szrj
214938fd1498Szrj /* If requested, warn about function definitions where the function will
215038fd1498Szrj return a value (usually of some struct or union type) which itself will
215138fd1498Szrj take up a lot of stack space. */
215238fd1498Szrj if (warn_larger_than && !DECL_EXTERNAL (decl) && TREE_TYPE (decl))
215338fd1498Szrj {
215438fd1498Szrj tree ret_type = TREE_TYPE (TREE_TYPE (decl));
215538fd1498Szrj
215638fd1498Szrj if (ret_type && TYPE_SIZE_UNIT (ret_type)
215738fd1498Szrj && TREE_CODE (TYPE_SIZE_UNIT (ret_type)) == INTEGER_CST
215838fd1498Szrj && compare_tree_int (TYPE_SIZE_UNIT (ret_type),
215938fd1498Szrj larger_than_size) > 0)
216038fd1498Szrj {
216138fd1498Szrj unsigned int size_as_int
216238fd1498Szrj = TREE_INT_CST_LOW (TYPE_SIZE_UNIT (ret_type));
216338fd1498Szrj
216438fd1498Szrj if (compare_tree_int (TYPE_SIZE_UNIT (ret_type), size_as_int) == 0)
216538fd1498Szrj warning (OPT_Wlarger_than_, "size of return value of %q+D is %u bytes",
216638fd1498Szrj decl, size_as_int);
216738fd1498Szrj else
216838fd1498Szrj warning (OPT_Wlarger_than_, "size of return value of %q+D is larger than %wd bytes",
216938fd1498Szrj decl, larger_than_size);
217038fd1498Szrj }
217138fd1498Szrj }
217238fd1498Szrj
217338fd1498Szrj gimple_set_body (decl, NULL);
217438fd1498Szrj if (DECL_STRUCT_FUNCTION (decl) == 0
217538fd1498Szrj && !cgraph_node::get (decl)->origin)
217638fd1498Szrj {
217738fd1498Szrj /* Stop pointing to the local nodes about to be freed.
217838fd1498Szrj But DECL_INITIAL must remain nonzero so we know this
217938fd1498Szrj was an actual function definition.
218038fd1498Szrj For a nested function, this is done in c_pop_function_context.
218138fd1498Szrj If rest_of_compilation set this to 0, leave it 0. */
218238fd1498Szrj if (DECL_INITIAL (decl) != 0)
218338fd1498Szrj DECL_INITIAL (decl) = error_mark_node;
218438fd1498Szrj }
218538fd1498Szrj
218638fd1498Szrj input_location = saved_loc;
218738fd1498Szrj
218838fd1498Szrj ggc_collect ();
218938fd1498Szrj timevar_pop (TV_REST_OF_COMPILATION);
219038fd1498Szrj
219138fd1498Szrj /* Make sure that BE didn't give up on compiling. */
219238fd1498Szrj gcc_assert (TREE_ASM_WRITTEN (decl));
219338fd1498Szrj if (cfun)
219438fd1498Szrj pop_cfun ();
219538fd1498Szrj
219638fd1498Szrj /* It would make a lot more sense to output thunks before function body to get more
219738fd1498Szrj forward and lest backwarding jumps. This however would need solving problem
219838fd1498Szrj with comdats. See PR48668. Also aliases must come after function itself to
219938fd1498Szrj make one pass assemblers, like one on AIX, happy. See PR 50689.
220038fd1498Szrj FIXME: Perhaps thunks should be move before function IFF they are not in comdat
220138fd1498Szrj groups. */
220238fd1498Szrj assemble_thunks_and_aliases ();
220338fd1498Szrj release_body ();
220438fd1498Szrj /* Eliminate all call edges. This is important so the GIMPLE_CALL no longer
220538fd1498Szrj points to the dead function body. */
220638fd1498Szrj remove_callees ();
220738fd1498Szrj remove_all_references ();
220838fd1498Szrj }
220938fd1498Szrj
221038fd1498Szrj /* Node comparer that is responsible for the order that corresponds
221138fd1498Szrj to time when a function was launched for the first time. */
221238fd1498Szrj
221338fd1498Szrj static int
node_cmp(const void * pa,const void * pb)221438fd1498Szrj node_cmp (const void *pa, const void *pb)
221538fd1498Szrj {
221638fd1498Szrj const cgraph_node *a = *(const cgraph_node * const *) pa;
221738fd1498Szrj const cgraph_node *b = *(const cgraph_node * const *) pb;
221838fd1498Szrj
221938fd1498Szrj /* Functions with time profile must be before these without profile. */
222038fd1498Szrj if (!a->tp_first_run || !b->tp_first_run)
222138fd1498Szrj return a->tp_first_run - b->tp_first_run;
222238fd1498Szrj
222338fd1498Szrj return a->tp_first_run != b->tp_first_run
222438fd1498Szrj ? b->tp_first_run - a->tp_first_run
222538fd1498Szrj : b->order - a->order;
222638fd1498Szrj }
222738fd1498Szrj
222838fd1498Szrj /* Expand all functions that must be output.
222938fd1498Szrj
223038fd1498Szrj Attempt to topologically sort the nodes so function is output when
223138fd1498Szrj all called functions are already assembled to allow data to be
223238fd1498Szrj propagated across the callgraph. Use a stack to get smaller distance
223338fd1498Szrj between a function and its callees (later we may choose to use a more
223438fd1498Szrj sophisticated algorithm for function reordering; we will likely want
223538fd1498Szrj to use subsections to make the output functions appear in top-down
223638fd1498Szrj order). */
223738fd1498Szrj
223838fd1498Szrj static void
expand_all_functions(void)223938fd1498Szrj expand_all_functions (void)
224038fd1498Szrj {
224138fd1498Szrj cgraph_node *node;
224238fd1498Szrj cgraph_node **order = XCNEWVEC (cgraph_node *,
224338fd1498Szrj symtab->cgraph_count);
224438fd1498Szrj unsigned int expanded_func_count = 0, profiled_func_count = 0;
224538fd1498Szrj int order_pos, new_order_pos = 0;
224638fd1498Szrj int i;
224738fd1498Szrj
224838fd1498Szrj order_pos = ipa_reverse_postorder (order);
224938fd1498Szrj gcc_assert (order_pos == symtab->cgraph_count);
225038fd1498Szrj
225138fd1498Szrj /* Garbage collector may remove inline clones we eliminate during
225238fd1498Szrj optimization. So we must be sure to not reference them. */
225338fd1498Szrj for (i = 0; i < order_pos; i++)
225438fd1498Szrj if (order[i]->process)
225538fd1498Szrj order[new_order_pos++] = order[i];
225638fd1498Szrj
225738fd1498Szrj if (flag_profile_reorder_functions)
225838fd1498Szrj qsort (order, new_order_pos, sizeof (cgraph_node *), node_cmp);
225938fd1498Szrj
226038fd1498Szrj for (i = new_order_pos - 1; i >= 0; i--)
226138fd1498Szrj {
226238fd1498Szrj node = order[i];
226338fd1498Szrj
226438fd1498Szrj if (node->process)
226538fd1498Szrj {
226638fd1498Szrj expanded_func_count++;
226738fd1498Szrj if(node->tp_first_run)
226838fd1498Szrj profiled_func_count++;
226938fd1498Szrj
227038fd1498Szrj if (symtab->dump_file)
227138fd1498Szrj fprintf (symtab->dump_file,
227238fd1498Szrj "Time profile order in expand_all_functions:%s:%d\n",
227338fd1498Szrj node->asm_name (), node->tp_first_run);
227438fd1498Szrj node->process = 0;
227538fd1498Szrj node->expand ();
227638fd1498Szrj }
227738fd1498Szrj }
227838fd1498Szrj
227938fd1498Szrj if (dump_file)
228038fd1498Szrj fprintf (dump_file, "Expanded functions with time profile (%s):%u/%u\n",
228138fd1498Szrj main_input_filename, profiled_func_count, expanded_func_count);
228238fd1498Szrj
228338fd1498Szrj if (symtab->dump_file && flag_profile_reorder_functions)
228438fd1498Szrj fprintf (symtab->dump_file, "Expanded functions with time profile:%u/%u\n",
228538fd1498Szrj profiled_func_count, expanded_func_count);
228638fd1498Szrj
228738fd1498Szrj symtab->process_new_functions ();
228838fd1498Szrj free_gimplify_stack ();
228938fd1498Szrj
229038fd1498Szrj free (order);
229138fd1498Szrj }
229238fd1498Szrj
229338fd1498Szrj /* This is used to sort the node types by the cgraph order number. */
229438fd1498Szrj
229538fd1498Szrj enum cgraph_order_sort_kind
229638fd1498Szrj {
229738fd1498Szrj ORDER_UNDEFINED = 0,
229838fd1498Szrj ORDER_FUNCTION,
229938fd1498Szrj ORDER_VAR,
230038fd1498Szrj ORDER_VAR_UNDEF,
230138fd1498Szrj ORDER_ASM
230238fd1498Szrj };
230338fd1498Szrj
230438fd1498Szrj struct cgraph_order_sort
230538fd1498Szrj {
230638fd1498Szrj enum cgraph_order_sort_kind kind;
230738fd1498Szrj union
230838fd1498Szrj {
230938fd1498Szrj cgraph_node *f;
231038fd1498Szrj varpool_node *v;
231138fd1498Szrj asm_node *a;
231238fd1498Szrj } u;
231338fd1498Szrj };
231438fd1498Szrj
231538fd1498Szrj /* Output all functions, variables, and asm statements in the order
231638fd1498Szrj according to their order fields, which is the order in which they
231738fd1498Szrj appeared in the file. This implements -fno-toplevel-reorder. In
231838fd1498Szrj this mode we may output functions and variables which don't really
231938fd1498Szrj need to be output. */
232038fd1498Szrj
232138fd1498Szrj static void
output_in_order(void)232238fd1498Szrj output_in_order (void)
232338fd1498Szrj {
232438fd1498Szrj int max;
232538fd1498Szrj cgraph_order_sort *nodes;
232638fd1498Szrj int i;
232738fd1498Szrj cgraph_node *pf;
232838fd1498Szrj varpool_node *pv;
232938fd1498Szrj asm_node *pa;
233038fd1498Szrj max = symtab->order;
233138fd1498Szrj nodes = XCNEWVEC (cgraph_order_sort, max);
233238fd1498Szrj
233338fd1498Szrj FOR_EACH_DEFINED_FUNCTION (pf)
233438fd1498Szrj {
233538fd1498Szrj if (pf->process && !pf->thunk.thunk_p && !pf->alias)
233638fd1498Szrj {
233738fd1498Szrj if (!pf->no_reorder)
233838fd1498Szrj continue;
233938fd1498Szrj i = pf->order;
234038fd1498Szrj gcc_assert (nodes[i].kind == ORDER_UNDEFINED);
234138fd1498Szrj nodes[i].kind = ORDER_FUNCTION;
234238fd1498Szrj nodes[i].u.f = pf;
234338fd1498Szrj }
234438fd1498Szrj }
234538fd1498Szrj
234638fd1498Szrj /* There is a similar loop in symbol_table::output_variables.
234738fd1498Szrj Please keep them in sync. */
234838fd1498Szrj FOR_EACH_VARIABLE (pv)
234938fd1498Szrj {
235038fd1498Szrj if (!pv->no_reorder)
235138fd1498Szrj continue;
235238fd1498Szrj if (DECL_HARD_REGISTER (pv->decl)
235338fd1498Szrj || DECL_HAS_VALUE_EXPR_P (pv->decl))
235438fd1498Szrj continue;
235538fd1498Szrj i = pv->order;
235638fd1498Szrj gcc_assert (nodes[i].kind == ORDER_UNDEFINED);
235738fd1498Szrj nodes[i].kind = pv->definition ? ORDER_VAR : ORDER_VAR_UNDEF;
235838fd1498Szrj nodes[i].u.v = pv;
235938fd1498Szrj }
236038fd1498Szrj
236138fd1498Szrj for (pa = symtab->first_asm_symbol (); pa; pa = pa->next)
236238fd1498Szrj {
236338fd1498Szrj i = pa->order;
236438fd1498Szrj gcc_assert (nodes[i].kind == ORDER_UNDEFINED);
236538fd1498Szrj nodes[i].kind = ORDER_ASM;
236638fd1498Szrj nodes[i].u.a = pa;
236738fd1498Szrj }
236838fd1498Szrj
236938fd1498Szrj /* In toplevel reorder mode we output all statics; mark them as needed. */
237038fd1498Szrj
237138fd1498Szrj for (i = 0; i < max; ++i)
237238fd1498Szrj if (nodes[i].kind == ORDER_VAR)
237338fd1498Szrj nodes[i].u.v->finalize_named_section_flags ();
237438fd1498Szrj
237538fd1498Szrj for (i = 0; i < max; ++i)
237638fd1498Szrj {
237738fd1498Szrj switch (nodes[i].kind)
237838fd1498Szrj {
237938fd1498Szrj case ORDER_FUNCTION:
238038fd1498Szrj nodes[i].u.f->process = 0;
238138fd1498Szrj nodes[i].u.f->expand ();
238238fd1498Szrj break;
238338fd1498Szrj
238438fd1498Szrj case ORDER_VAR:
238538fd1498Szrj nodes[i].u.v->assemble_decl ();
238638fd1498Szrj break;
238738fd1498Szrj
238838fd1498Szrj case ORDER_VAR_UNDEF:
238938fd1498Szrj assemble_undefined_decl (nodes[i].u.v->decl);
239038fd1498Szrj break;
239138fd1498Szrj
239238fd1498Szrj case ORDER_ASM:
239338fd1498Szrj assemble_asm (nodes[i].u.a->asm_str);
239438fd1498Szrj break;
239538fd1498Szrj
239638fd1498Szrj case ORDER_UNDEFINED:
239738fd1498Szrj break;
239838fd1498Szrj
239938fd1498Szrj default:
240038fd1498Szrj gcc_unreachable ();
240138fd1498Szrj }
240238fd1498Szrj }
240338fd1498Szrj
240438fd1498Szrj symtab->clear_asm_symbols ();
240538fd1498Szrj
240638fd1498Szrj free (nodes);
240738fd1498Szrj }
240838fd1498Szrj
240938fd1498Szrj static void
ipa_passes(void)241038fd1498Szrj ipa_passes (void)
241138fd1498Szrj {
241238fd1498Szrj gcc::pass_manager *passes = g->get_passes ();
241338fd1498Szrj
241438fd1498Szrj set_cfun (NULL);
241538fd1498Szrj current_function_decl = NULL;
241638fd1498Szrj gimple_register_cfg_hooks ();
241738fd1498Szrj bitmap_obstack_initialize (NULL);
241838fd1498Szrj
241938fd1498Szrj invoke_plugin_callbacks (PLUGIN_ALL_IPA_PASSES_START, NULL);
242038fd1498Szrj
242138fd1498Szrj if (!in_lto_p)
242238fd1498Szrj {
242338fd1498Szrj execute_ipa_pass_list (passes->all_small_ipa_passes);
242438fd1498Szrj if (seen_error ())
242538fd1498Szrj return;
242638fd1498Szrj }
242738fd1498Szrj
242838fd1498Szrj /* This extra symtab_remove_unreachable_nodes pass tends to catch some
242938fd1498Szrj devirtualization and other changes where removal iterate. */
243038fd1498Szrj symtab->remove_unreachable_nodes (symtab->dump_file);
243138fd1498Szrj
243238fd1498Szrj /* If pass_all_early_optimizations was not scheduled, the state of
243338fd1498Szrj the cgraph will not be properly updated. Update it now. */
243438fd1498Szrj if (symtab->state < IPA_SSA)
243538fd1498Szrj symtab->state = IPA_SSA;
243638fd1498Szrj
243738fd1498Szrj if (!in_lto_p)
243838fd1498Szrj {
243938fd1498Szrj /* Generate coverage variables and constructors. */
244038fd1498Szrj coverage_finish ();
244138fd1498Szrj
244238fd1498Szrj /* Process new functions added. */
244338fd1498Szrj set_cfun (NULL);
244438fd1498Szrj current_function_decl = NULL;
244538fd1498Szrj symtab->process_new_functions ();
244638fd1498Szrj
244738fd1498Szrj execute_ipa_summary_passes
244838fd1498Szrj ((ipa_opt_pass_d *) passes->all_regular_ipa_passes);
244938fd1498Szrj }
245038fd1498Szrj
245138fd1498Szrj /* Some targets need to handle LTO assembler output specially. */
245238fd1498Szrj if (flag_generate_lto || flag_generate_offload)
245338fd1498Szrj targetm.asm_out.lto_start ();
245438fd1498Szrj
245538fd1498Szrj if (!in_lto_p)
245638fd1498Szrj {
245738fd1498Szrj if (g->have_offload)
245838fd1498Szrj {
245938fd1498Szrj section_name_prefix = OFFLOAD_SECTION_NAME_PREFIX;
246038fd1498Szrj lto_stream_offload_p = true;
246138fd1498Szrj ipa_write_summaries ();
246238fd1498Szrj lto_stream_offload_p = false;
246338fd1498Szrj }
246438fd1498Szrj if (flag_lto)
246538fd1498Szrj {
246638fd1498Szrj section_name_prefix = LTO_SECTION_NAME_PREFIX;
246738fd1498Szrj lto_stream_offload_p = false;
246838fd1498Szrj ipa_write_summaries ();
246938fd1498Szrj }
247038fd1498Szrj }
247138fd1498Szrj
247238fd1498Szrj if (flag_generate_lto || flag_generate_offload)
247338fd1498Szrj targetm.asm_out.lto_end ();
247438fd1498Szrj
247538fd1498Szrj if (!flag_ltrans && (in_lto_p || !flag_lto || flag_fat_lto_objects))
247638fd1498Szrj execute_ipa_pass_list (passes->all_regular_ipa_passes);
247738fd1498Szrj invoke_plugin_callbacks (PLUGIN_ALL_IPA_PASSES_END, NULL);
247838fd1498Szrj
247938fd1498Szrj bitmap_obstack_release (NULL);
248038fd1498Szrj }
248138fd1498Szrj
248238fd1498Szrj
248338fd1498Szrj /* Return string alias is alias of. */
248438fd1498Szrj
248538fd1498Szrj static tree
get_alias_symbol(tree decl)248638fd1498Szrj get_alias_symbol (tree decl)
248738fd1498Szrj {
248838fd1498Szrj tree alias = lookup_attribute ("alias", DECL_ATTRIBUTES (decl));
248938fd1498Szrj return get_identifier (TREE_STRING_POINTER
249038fd1498Szrj (TREE_VALUE (TREE_VALUE (alias))));
249138fd1498Szrj }
249238fd1498Szrj
249338fd1498Szrj
249438fd1498Szrj /* Weakrefs may be associated to external decls and thus not output
249538fd1498Szrj at expansion time. Emit all necessary aliases. */
249638fd1498Szrj
249738fd1498Szrj void
output_weakrefs(void)249838fd1498Szrj symbol_table::output_weakrefs (void)
249938fd1498Szrj {
250038fd1498Szrj symtab_node *node;
250138fd1498Szrj cgraph_node *cnode;
250238fd1498Szrj FOR_EACH_SYMBOL (node)
250338fd1498Szrj if (node->alias
250438fd1498Szrj && !TREE_ASM_WRITTEN (node->decl)
250538fd1498Szrj && (!(cnode = dyn_cast <cgraph_node *> (node))
250638fd1498Szrj || !cnode->instrumented_version
250738fd1498Szrj || !TREE_ASM_WRITTEN (cnode->instrumented_version->decl))
250838fd1498Szrj && node->weakref)
250938fd1498Szrj {
251038fd1498Szrj tree target;
251138fd1498Szrj
251238fd1498Szrj /* Weakrefs are special by not requiring target definition in current
251338fd1498Szrj compilation unit. It is thus bit hard to work out what we want to
251438fd1498Szrj alias.
251538fd1498Szrj When alias target is defined, we need to fetch it from symtab reference,
251638fd1498Szrj otherwise it is pointed to by alias_target. */
251738fd1498Szrj if (node->alias_target)
251838fd1498Szrj target = (DECL_P (node->alias_target)
251938fd1498Szrj ? DECL_ASSEMBLER_NAME (node->alias_target)
252038fd1498Szrj : node->alias_target);
252138fd1498Szrj else if (node->analyzed)
252238fd1498Szrj target = DECL_ASSEMBLER_NAME (node->get_alias_target ()->decl);
252338fd1498Szrj else
252438fd1498Szrj {
252538fd1498Szrj gcc_unreachable ();
252638fd1498Szrj target = get_alias_symbol (node->decl);
252738fd1498Szrj }
252838fd1498Szrj do_assemble_alias (node->decl, target);
252938fd1498Szrj }
253038fd1498Szrj }
253138fd1498Szrj
253238fd1498Szrj /* Perform simple optimizations based on callgraph. */
253338fd1498Szrj
253438fd1498Szrj void
compile(void)253538fd1498Szrj symbol_table::compile (void)
253638fd1498Szrj {
253738fd1498Szrj if (seen_error ())
253838fd1498Szrj return;
253938fd1498Szrj
254038fd1498Szrj symtab_node::checking_verify_symtab_nodes ();
254138fd1498Szrj
254238fd1498Szrj timevar_push (TV_CGRAPHOPT);
254338fd1498Szrj if (pre_ipa_mem_report)
254438fd1498Szrj {
254538fd1498Szrj fprintf (stderr, "Memory consumption before IPA\n");
254638fd1498Szrj dump_memory_report (false);
254738fd1498Szrj }
254838fd1498Szrj if (!quiet_flag)
254938fd1498Szrj fprintf (stderr, "Performing interprocedural optimizations\n");
255038fd1498Szrj state = IPA;
255138fd1498Szrj
255238fd1498Szrj /* If LTO is enabled, initialize the streamer hooks needed by GIMPLE. */
255338fd1498Szrj if (flag_generate_lto || flag_generate_offload)
255438fd1498Szrj lto_streamer_hooks_init ();
255538fd1498Szrj
255638fd1498Szrj /* Don't run the IPA passes if there was any error or sorry messages. */
255738fd1498Szrj if (!seen_error ())
255838fd1498Szrj ipa_passes ();
255938fd1498Szrj
256038fd1498Szrj /* Do nothing else if any IPA pass found errors or if we are just streaming LTO. */
256138fd1498Szrj if (seen_error ()
256238fd1498Szrj || (!in_lto_p && flag_lto && !flag_fat_lto_objects))
256338fd1498Szrj {
256438fd1498Szrj timevar_pop (TV_CGRAPHOPT);
256538fd1498Szrj return;
256638fd1498Szrj }
256738fd1498Szrj
256838fd1498Szrj global_info_ready = true;
256938fd1498Szrj if (dump_file)
257038fd1498Szrj {
257138fd1498Szrj fprintf (dump_file, "Optimized ");
257238fd1498Szrj symtab->dump (dump_file);
257338fd1498Szrj }
257438fd1498Szrj if (post_ipa_mem_report)
257538fd1498Szrj {
257638fd1498Szrj fprintf (stderr, "Memory consumption after IPA\n");
257738fd1498Szrj dump_memory_report (false);
257838fd1498Szrj }
257938fd1498Szrj timevar_pop (TV_CGRAPHOPT);
258038fd1498Szrj
258138fd1498Szrj /* Output everything. */
258238fd1498Szrj switch_to_section (text_section);
258338fd1498Szrj (*debug_hooks->assembly_start) ();
258438fd1498Szrj if (!quiet_flag)
258538fd1498Szrj fprintf (stderr, "Assembling functions:\n");
258638fd1498Szrj symtab_node::checking_verify_symtab_nodes ();
258738fd1498Szrj
258838fd1498Szrj bitmap_obstack_initialize (NULL);
258938fd1498Szrj execute_ipa_pass_list (g->get_passes ()->all_late_ipa_passes);
259038fd1498Szrj bitmap_obstack_release (NULL);
259138fd1498Szrj mark_functions_to_output ();
259238fd1498Szrj
259338fd1498Szrj /* When weakref support is missing, we automatically translate all
259438fd1498Szrj references to NODE to references to its ultimate alias target.
259538fd1498Szrj The renaming mechanizm uses flag IDENTIFIER_TRANSPARENT_ALIAS and
259638fd1498Szrj TREE_CHAIN.
259738fd1498Szrj
259838fd1498Szrj Set up this mapping before we output any assembler but once we are sure
259938fd1498Szrj that all symbol renaming is done.
260038fd1498Szrj
260138fd1498Szrj FIXME: All this uglyness can go away if we just do renaming at gimple
260238fd1498Szrj level by physically rewritting the IL. At the moment we can only redirect
260338fd1498Szrj calls, so we need infrastructure for renaming references as well. */
260438fd1498Szrj #ifndef ASM_OUTPUT_WEAKREF
260538fd1498Szrj symtab_node *node;
260638fd1498Szrj
260738fd1498Szrj FOR_EACH_SYMBOL (node)
260838fd1498Szrj if (node->alias
260938fd1498Szrj && lookup_attribute ("weakref", DECL_ATTRIBUTES (node->decl)))
261038fd1498Szrj {
261138fd1498Szrj IDENTIFIER_TRANSPARENT_ALIAS
261238fd1498Szrj (DECL_ASSEMBLER_NAME (node->decl)) = 1;
261338fd1498Szrj TREE_CHAIN (DECL_ASSEMBLER_NAME (node->decl))
261438fd1498Szrj = (node->alias_target ? node->alias_target
261538fd1498Szrj : DECL_ASSEMBLER_NAME (node->get_alias_target ()->decl));
261638fd1498Szrj }
261738fd1498Szrj #endif
261838fd1498Szrj
261938fd1498Szrj state = EXPANSION;
262038fd1498Szrj
262138fd1498Szrj /* Output first asm statements and anything ordered. The process
262238fd1498Szrj flag is cleared for these nodes, so we skip them later. */
262338fd1498Szrj output_in_order ();
262438fd1498Szrj expand_all_functions ();
262538fd1498Szrj output_variables ();
262638fd1498Szrj
262738fd1498Szrj process_new_functions ();
262838fd1498Szrj state = FINISHED;
262938fd1498Szrj output_weakrefs ();
263038fd1498Szrj
263138fd1498Szrj if (dump_file)
263238fd1498Szrj {
263338fd1498Szrj fprintf (dump_file, "\nFinal ");
263438fd1498Szrj symtab->dump (dump_file);
263538fd1498Szrj }
263638fd1498Szrj if (!flag_checking)
263738fd1498Szrj return;
263838fd1498Szrj symtab_node::verify_symtab_nodes ();
263938fd1498Szrj /* Double check that all inline clones are gone and that all
264038fd1498Szrj function bodies have been released from memory. */
264138fd1498Szrj if (!seen_error ())
264238fd1498Szrj {
264338fd1498Szrj cgraph_node *node;
264438fd1498Szrj bool error_found = false;
264538fd1498Szrj
264638fd1498Szrj FOR_EACH_DEFINED_FUNCTION (node)
264738fd1498Szrj if (node->global.inlined_to
264838fd1498Szrj || gimple_has_body_p (node->decl))
264938fd1498Szrj {
265038fd1498Szrj error_found = true;
265138fd1498Szrj node->debug ();
265238fd1498Szrj }
265338fd1498Szrj if (error_found)
265438fd1498Szrj internal_error ("nodes with unreleased memory found");
265538fd1498Szrj }
265638fd1498Szrj }
265738fd1498Szrj
265838fd1498Szrj
265938fd1498Szrj /* Analyze the whole compilation unit once it is parsed completely. */
266038fd1498Szrj
266138fd1498Szrj void
finalize_compilation_unit(void)266238fd1498Szrj symbol_table::finalize_compilation_unit (void)
266338fd1498Szrj {
266438fd1498Szrj timevar_push (TV_CGRAPH);
266538fd1498Szrj
266638fd1498Szrj /* If we're here there's no current function anymore. Some frontends
266738fd1498Szrj are lazy in clearing these. */
266838fd1498Szrj current_function_decl = NULL;
266938fd1498Szrj set_cfun (NULL);
267038fd1498Szrj
267138fd1498Szrj /* Do not skip analyzing the functions if there were errors, we
267238fd1498Szrj miss diagnostics for following functions otherwise. */
267338fd1498Szrj
267438fd1498Szrj /* Emit size functions we didn't inline. */
267538fd1498Szrj finalize_size_functions ();
267638fd1498Szrj
267738fd1498Szrj /* Mark alias targets necessary and emit diagnostics. */
267838fd1498Szrj handle_alias_pairs ();
267938fd1498Szrj
268038fd1498Szrj if (!quiet_flag)
268138fd1498Szrj {
268238fd1498Szrj fprintf (stderr, "\nAnalyzing compilation unit\n");
268338fd1498Szrj fflush (stderr);
268438fd1498Szrj }
268538fd1498Szrj
268638fd1498Szrj if (flag_dump_passes)
268738fd1498Szrj dump_passes ();
268838fd1498Szrj
268938fd1498Szrj /* Gimplify and lower all functions, compute reachability and
269038fd1498Szrj remove unreachable nodes. */
269138fd1498Szrj analyze_functions (/*first_time=*/true);
269238fd1498Szrj
269338fd1498Szrj /* Mark alias targets necessary and emit diagnostics. */
269438fd1498Szrj handle_alias_pairs ();
269538fd1498Szrj
269638fd1498Szrj /* Gimplify and lower thunks. */
269738fd1498Szrj analyze_functions (/*first_time=*/false);
269838fd1498Szrj
269938fd1498Szrj /* Offloading requires LTO infrastructure. */
270038fd1498Szrj if (!in_lto_p && g->have_offload)
270138fd1498Szrj flag_generate_offload = 1;
270238fd1498Szrj
270338fd1498Szrj if (!seen_error ())
270438fd1498Szrj {
270538fd1498Szrj /* Emit early debug for reachable functions, and by consequence,
270638fd1498Szrj locally scoped symbols. */
270738fd1498Szrj struct cgraph_node *cnode;
270838fd1498Szrj FOR_EACH_FUNCTION_WITH_GIMPLE_BODY (cnode)
270938fd1498Szrj (*debug_hooks->early_global_decl) (cnode->decl);
271038fd1498Szrj
271138fd1498Szrj /* Clean up anything that needs cleaning up after initial debug
271238fd1498Szrj generation. */
271338fd1498Szrj (*debug_hooks->early_finish) (main_input_filename);
271438fd1498Szrj }
271538fd1498Szrj
271638fd1498Szrj /* Finally drive the pass manager. */
271738fd1498Szrj compile ();
271838fd1498Szrj
271938fd1498Szrj timevar_pop (TV_CGRAPH);
272038fd1498Szrj }
272138fd1498Szrj
272238fd1498Szrj /* Reset all state within cgraphunit.c so that we can rerun the compiler
272338fd1498Szrj within the same process. For use by toplev::finalize. */
272438fd1498Szrj
272538fd1498Szrj void
cgraphunit_c_finalize(void)272638fd1498Szrj cgraphunit_c_finalize (void)
272738fd1498Szrj {
272838fd1498Szrj gcc_assert (cgraph_new_nodes.length () == 0);
272938fd1498Szrj cgraph_new_nodes.truncate (0);
273038fd1498Szrj
273138fd1498Szrj vtable_entry_type = NULL;
273238fd1498Szrj queued_nodes = &symtab_terminator;
273338fd1498Szrj
273438fd1498Szrj first_analyzed = NULL;
273538fd1498Szrj first_analyzed_var = NULL;
273638fd1498Szrj }
273738fd1498Szrj
273838fd1498Szrj /* Creates a wrapper from cgraph_node to TARGET node. Thunk is used for this
273938fd1498Szrj kind of wrapper method. */
274038fd1498Szrj
274138fd1498Szrj void
create_wrapper(cgraph_node * target)274238fd1498Szrj cgraph_node::create_wrapper (cgraph_node *target)
274338fd1498Szrj {
274438fd1498Szrj /* Preserve DECL_RESULT so we get right by reference flag. */
274538fd1498Szrj tree decl_result = DECL_RESULT (decl);
274638fd1498Szrj
274738fd1498Szrj /* Remove the function's body but keep arguments to be reused
274838fd1498Szrj for thunk. */
274938fd1498Szrj release_body (true);
275038fd1498Szrj reset ();
275138fd1498Szrj
275238fd1498Szrj DECL_UNINLINABLE (decl) = false;
275338fd1498Szrj DECL_RESULT (decl) = decl_result;
275438fd1498Szrj DECL_INITIAL (decl) = NULL;
275538fd1498Szrj allocate_struct_function (decl, false);
275638fd1498Szrj set_cfun (NULL);
275738fd1498Szrj
275838fd1498Szrj /* Turn alias into thunk and expand it into GIMPLE representation. */
275938fd1498Szrj definition = true;
276038fd1498Szrj
276138fd1498Szrj memset (&thunk, 0, sizeof (cgraph_thunk_info));
276238fd1498Szrj thunk.thunk_p = true;
276338fd1498Szrj create_edge (target, NULL, count);
276438fd1498Szrj callees->can_throw_external = !TREE_NOTHROW (target->decl);
276538fd1498Szrj
276638fd1498Szrj tree arguments = DECL_ARGUMENTS (decl);
276738fd1498Szrj
276838fd1498Szrj while (arguments)
276938fd1498Szrj {
277038fd1498Szrj TREE_ADDRESSABLE (arguments) = false;
277138fd1498Szrj arguments = TREE_CHAIN (arguments);
277238fd1498Szrj }
277338fd1498Szrj
277438fd1498Szrj expand_thunk (false, true);
277538fd1498Szrj
277638fd1498Szrj /* Inline summary set-up. */
277738fd1498Szrj analyze ();
277838fd1498Szrj inline_analyze_function (this);
277938fd1498Szrj }
278038fd1498Szrj
278138fd1498Szrj #include "gt-cgraphunit.h"
2782