xref: /netbsd/external/gpl3/gcc/dist/gcc/cgraphbuild.cc (revision f0fbc68b)
1*f0fbc68bSmrg /* Callgraph construction.
2*f0fbc68bSmrg    Copyright (C) 2003-2022 Free Software Foundation, Inc.
3*f0fbc68bSmrg    Contributed by Jan Hubicka
4*f0fbc68bSmrg 
5*f0fbc68bSmrg This file is part of GCC.
6*f0fbc68bSmrg 
7*f0fbc68bSmrg GCC is free software; you can redistribute it and/or modify it under
8*f0fbc68bSmrg the terms of the GNU General Public License as published by the Free
9*f0fbc68bSmrg Software Foundation; either version 3, or (at your option) any later
10*f0fbc68bSmrg version.
11*f0fbc68bSmrg 
12*f0fbc68bSmrg GCC is distributed in the hope that it will be useful, but WITHOUT ANY
13*f0fbc68bSmrg WARRANTY; without even the implied warranty of MERCHANTABILITY or
14*f0fbc68bSmrg FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
15*f0fbc68bSmrg for more details.
16*f0fbc68bSmrg 
17*f0fbc68bSmrg You should have received a copy of the GNU General Public License
18*f0fbc68bSmrg along with GCC; see the file COPYING3.  If not see
19*f0fbc68bSmrg <http://www.gnu.org/licenses/>.  */
20*f0fbc68bSmrg 
21*f0fbc68bSmrg #include "config.h"
22*f0fbc68bSmrg #include "system.h"
23*f0fbc68bSmrg #include "coretypes.h"
24*f0fbc68bSmrg #include "backend.h"
25*f0fbc68bSmrg #include "tree.h"
26*f0fbc68bSmrg #include "gimple.h"
27*f0fbc68bSmrg #include "tree-pass.h"
28*f0fbc68bSmrg #include "cgraph.h"
29*f0fbc68bSmrg #include "gimple-fold.h"
30*f0fbc68bSmrg #include "gimple-iterator.h"
31*f0fbc68bSmrg #include "gimple-walk.h"
32*f0fbc68bSmrg #include "ipa-utils.h"
33*f0fbc68bSmrg #include "except.h"
34*f0fbc68bSmrg 
35*f0fbc68bSmrg /* Context of record_reference.  */
36*f0fbc68bSmrg struct record_reference_ctx
37*f0fbc68bSmrg {
38*f0fbc68bSmrg   bool only_vars;
39*f0fbc68bSmrg   struct varpool_node *varpool_node;
40*f0fbc68bSmrg };
41*f0fbc68bSmrg 
42*f0fbc68bSmrg /* Walk tree and record all calls and references to functions/variables.
43*f0fbc68bSmrg    Called via walk_tree: TP is pointer to tree to be examined.
44*f0fbc68bSmrg    When DATA is non-null, record references to callgraph.
45*f0fbc68bSmrg    */
46*f0fbc68bSmrg 
47*f0fbc68bSmrg static tree
record_reference(tree * tp,int * walk_subtrees,void * data)48*f0fbc68bSmrg record_reference (tree *tp, int *walk_subtrees, void *data)
49*f0fbc68bSmrg {
50*f0fbc68bSmrg   tree t = *tp;
51*f0fbc68bSmrg   tree decl;
52*f0fbc68bSmrg   record_reference_ctx *ctx = (record_reference_ctx *)data;
53*f0fbc68bSmrg 
54*f0fbc68bSmrg   t = canonicalize_constructor_val (t, NULL);
55*f0fbc68bSmrg   if (!t)
56*f0fbc68bSmrg     t = *tp;
57*f0fbc68bSmrg   else if (t != *tp)
58*f0fbc68bSmrg     *tp = t;
59*f0fbc68bSmrg 
60*f0fbc68bSmrg   switch (TREE_CODE (t))
61*f0fbc68bSmrg     {
62*f0fbc68bSmrg     case VAR_DECL:
63*f0fbc68bSmrg     case FUNCTION_DECL:
64*f0fbc68bSmrg       gcc_unreachable ();
65*f0fbc68bSmrg       break;
66*f0fbc68bSmrg 
67*f0fbc68bSmrg     case FDESC_EXPR:
68*f0fbc68bSmrg     case ADDR_EXPR:
69*f0fbc68bSmrg       /* Record dereferences to the functions.  This makes the
70*f0fbc68bSmrg 	 functions reachable unconditionally.  */
71*f0fbc68bSmrg       decl = get_base_var (*tp);
72*f0fbc68bSmrg       if (TREE_CODE (decl) == FUNCTION_DECL)
73*f0fbc68bSmrg 	{
74*f0fbc68bSmrg 	  cgraph_node *node = cgraph_node::get_create (decl);
75*f0fbc68bSmrg 	  if (!ctx->only_vars)
76*f0fbc68bSmrg 	    node->mark_address_taken ();
77*f0fbc68bSmrg 	  ctx->varpool_node->create_reference (node, IPA_REF_ADDR);
78*f0fbc68bSmrg 	}
79*f0fbc68bSmrg 
80*f0fbc68bSmrg       if (VAR_P (decl))
81*f0fbc68bSmrg 	{
82*f0fbc68bSmrg 	  varpool_node *vnode = varpool_node::get_create (decl);
83*f0fbc68bSmrg 	  ctx->varpool_node->create_reference (vnode, IPA_REF_ADDR);
84*f0fbc68bSmrg 	}
85*f0fbc68bSmrg       *walk_subtrees = 0;
86*f0fbc68bSmrg       break;
87*f0fbc68bSmrg 
88*f0fbc68bSmrg     default:
89*f0fbc68bSmrg       /* Save some cycles by not walking types and declaration as we
90*f0fbc68bSmrg 	 won't find anything useful there anyway.  */
91*f0fbc68bSmrg       if (IS_TYPE_OR_DECL_P (*tp))
92*f0fbc68bSmrg 	{
93*f0fbc68bSmrg 	  *walk_subtrees = 0;
94*f0fbc68bSmrg 	  break;
95*f0fbc68bSmrg 	}
96*f0fbc68bSmrg       break;
97*f0fbc68bSmrg     }
98*f0fbc68bSmrg 
99*f0fbc68bSmrg   return NULL_TREE;
100*f0fbc68bSmrg }
101*f0fbc68bSmrg 
102*f0fbc68bSmrg /* Record references to typeinfos in the type list LIST.  */
103*f0fbc68bSmrg 
104*f0fbc68bSmrg static void
record_type_list(cgraph_node * node,tree list)105*f0fbc68bSmrg record_type_list (cgraph_node *node, tree list)
106*f0fbc68bSmrg {
107*f0fbc68bSmrg   for (; list; list = TREE_CHAIN (list))
108*f0fbc68bSmrg     {
109*f0fbc68bSmrg       tree type = TREE_VALUE (list);
110*f0fbc68bSmrg 
111*f0fbc68bSmrg       if (TYPE_P (type))
112*f0fbc68bSmrg 	type = lookup_type_for_runtime (type);
113*f0fbc68bSmrg       STRIP_NOPS (type);
114*f0fbc68bSmrg       if (TREE_CODE (type) == ADDR_EXPR)
115*f0fbc68bSmrg 	{
116*f0fbc68bSmrg 	  type = TREE_OPERAND (type, 0);
117*f0fbc68bSmrg 	  if (VAR_P (type))
118*f0fbc68bSmrg 	    {
119*f0fbc68bSmrg 	      varpool_node *vnode = varpool_node::get_create (type);
120*f0fbc68bSmrg 	      node->create_reference (vnode, IPA_REF_ADDR);
121*f0fbc68bSmrg 	    }
122*f0fbc68bSmrg 	}
123*f0fbc68bSmrg     }
124*f0fbc68bSmrg }
125*f0fbc68bSmrg 
126*f0fbc68bSmrg /* Record all references we will introduce by producing EH tables
127*f0fbc68bSmrg    for NODE.  */
128*f0fbc68bSmrg 
129*f0fbc68bSmrg static void
record_eh_tables(cgraph_node * node,function * fun)130*f0fbc68bSmrg record_eh_tables (cgraph_node *node, function *fun)
131*f0fbc68bSmrg {
132*f0fbc68bSmrg   eh_region i;
133*f0fbc68bSmrg 
134*f0fbc68bSmrg   if (DECL_FUNCTION_PERSONALITY (node->decl))
135*f0fbc68bSmrg     {
136*f0fbc68bSmrg       tree per_decl = DECL_FUNCTION_PERSONALITY (node->decl);
137*f0fbc68bSmrg       cgraph_node *per_node = cgraph_node::get_create (per_decl);
138*f0fbc68bSmrg 
139*f0fbc68bSmrg       node->create_reference (per_node, IPA_REF_ADDR);
140*f0fbc68bSmrg       per_node->mark_address_taken ();
141*f0fbc68bSmrg     }
142*f0fbc68bSmrg 
143*f0fbc68bSmrg   i = fun->eh->region_tree;
144*f0fbc68bSmrg   if (!i)
145*f0fbc68bSmrg     return;
146*f0fbc68bSmrg 
147*f0fbc68bSmrg   while (1)
148*f0fbc68bSmrg     {
149*f0fbc68bSmrg       switch (i->type)
150*f0fbc68bSmrg 	{
151*f0fbc68bSmrg 	case ERT_CLEANUP:
152*f0fbc68bSmrg 	case ERT_MUST_NOT_THROW:
153*f0fbc68bSmrg 	  break;
154*f0fbc68bSmrg 
155*f0fbc68bSmrg 	case ERT_TRY:
156*f0fbc68bSmrg 	  {
157*f0fbc68bSmrg 	    eh_catch c;
158*f0fbc68bSmrg 	    for (c = i->u.eh_try.first_catch; c; c = c->next_catch)
159*f0fbc68bSmrg 	      record_type_list (node, c->type_list);
160*f0fbc68bSmrg 	  }
161*f0fbc68bSmrg 	  break;
162*f0fbc68bSmrg 
163*f0fbc68bSmrg 	case ERT_ALLOWED_EXCEPTIONS:
164*f0fbc68bSmrg 	  record_type_list (node, i->u.allowed.type_list);
165*f0fbc68bSmrg 	  break;
166*f0fbc68bSmrg 	}
167*f0fbc68bSmrg       /* If there are sub-regions, process them.  */
168*f0fbc68bSmrg       if (i->inner)
169*f0fbc68bSmrg 	i = i->inner;
170*f0fbc68bSmrg       /* If there are peers, process them.  */
171*f0fbc68bSmrg       else if (i->next_peer)
172*f0fbc68bSmrg 	i = i->next_peer;
173*f0fbc68bSmrg       /* Otherwise, step back up the tree to the next peer.  */
174*f0fbc68bSmrg       else
175*f0fbc68bSmrg 	{
176*f0fbc68bSmrg 	  do
177*f0fbc68bSmrg 	    {
178*f0fbc68bSmrg 	      i = i->outer;
179*f0fbc68bSmrg 	      if (i == NULL)
180*f0fbc68bSmrg 		return;
181*f0fbc68bSmrg 	    }
182*f0fbc68bSmrg 	  while (i->next_peer == NULL);
183*f0fbc68bSmrg 	  i = i->next_peer;
184*f0fbc68bSmrg 	}
185*f0fbc68bSmrg     }
186*f0fbc68bSmrg }
187*f0fbc68bSmrg 
188*f0fbc68bSmrg /* Computes the frequency of the call statement so that it can be stored in
189*f0fbc68bSmrg    cgraph_edge.  BB is the basic block of the call statement.  */
190*f0fbc68bSmrg int
compute_call_stmt_bb_frequency(tree decl,basic_block bb)191*f0fbc68bSmrg compute_call_stmt_bb_frequency (tree decl, basic_block bb)
192*f0fbc68bSmrg {
193*f0fbc68bSmrg   return bb->count.to_cgraph_frequency
194*f0fbc68bSmrg       (ENTRY_BLOCK_PTR_FOR_FN (DECL_STRUCT_FUNCTION (decl))->count);
195*f0fbc68bSmrg }
196*f0fbc68bSmrg 
197*f0fbc68bSmrg /* Mark address taken in STMT.  */
198*f0fbc68bSmrg 
199*f0fbc68bSmrg static bool
mark_address(gimple * stmt,tree addr,tree,void * data)200*f0fbc68bSmrg mark_address (gimple *stmt, tree addr, tree, void *data)
201*f0fbc68bSmrg {
202*f0fbc68bSmrg   addr = get_base_address (addr);
203*f0fbc68bSmrg   if (TREE_CODE (addr) == FUNCTION_DECL)
204*f0fbc68bSmrg     {
205*f0fbc68bSmrg       cgraph_node *node = cgraph_node::get_create (addr);
206*f0fbc68bSmrg       node->mark_address_taken ();
207*f0fbc68bSmrg       ((symtab_node *)data)->create_reference (node, IPA_REF_ADDR, stmt);
208*f0fbc68bSmrg     }
209*f0fbc68bSmrg   else if (addr && VAR_P (addr)
210*f0fbc68bSmrg 	   && (TREE_STATIC (addr) || DECL_EXTERNAL (addr)))
211*f0fbc68bSmrg     {
212*f0fbc68bSmrg       varpool_node *vnode = varpool_node::get_create (addr);
213*f0fbc68bSmrg 
214*f0fbc68bSmrg       ((symtab_node *)data)->create_reference (vnode, IPA_REF_ADDR, stmt);
215*f0fbc68bSmrg     }
216*f0fbc68bSmrg 
217*f0fbc68bSmrg   return false;
218*f0fbc68bSmrg }
219*f0fbc68bSmrg 
220*f0fbc68bSmrg /* Mark load of T.  */
221*f0fbc68bSmrg 
222*f0fbc68bSmrg static bool
mark_load(gimple * stmt,tree t,tree,void * data)223*f0fbc68bSmrg mark_load (gimple *stmt, tree t, tree, void *data)
224*f0fbc68bSmrg {
225*f0fbc68bSmrg   t = get_base_address (t);
226*f0fbc68bSmrg   if (t && TREE_CODE (t) == FUNCTION_DECL)
227*f0fbc68bSmrg     {
228*f0fbc68bSmrg       /* ??? This can happen on platforms with descriptors when these are
229*f0fbc68bSmrg 	 directly manipulated in the code.  Pretend that it's an address.  */
230*f0fbc68bSmrg       cgraph_node *node = cgraph_node::get_create (t);
231*f0fbc68bSmrg       node->mark_address_taken ();
232*f0fbc68bSmrg       ((symtab_node *)data)->create_reference (node, IPA_REF_ADDR, stmt);
233*f0fbc68bSmrg     }
234*f0fbc68bSmrg   else if (t && VAR_P (t) && (TREE_STATIC (t) || DECL_EXTERNAL (t)))
235*f0fbc68bSmrg     {
236*f0fbc68bSmrg       varpool_node *vnode = varpool_node::get_create (t);
237*f0fbc68bSmrg 
238*f0fbc68bSmrg       ((symtab_node *)data)->create_reference (vnode, IPA_REF_LOAD, stmt);
239*f0fbc68bSmrg     }
240*f0fbc68bSmrg   return false;
241*f0fbc68bSmrg }
242*f0fbc68bSmrg 
243*f0fbc68bSmrg /* Mark store of T.  */
244*f0fbc68bSmrg 
245*f0fbc68bSmrg static bool
mark_store(gimple * stmt,tree t,tree,void * data)246*f0fbc68bSmrg mark_store (gimple *stmt, tree t, tree, void *data)
247*f0fbc68bSmrg {
248*f0fbc68bSmrg   t = get_base_address (t);
249*f0fbc68bSmrg   if (t && VAR_P (t) && (TREE_STATIC (t) || DECL_EXTERNAL (t)))
250*f0fbc68bSmrg     {
251*f0fbc68bSmrg       varpool_node *vnode = varpool_node::get_create (t);
252*f0fbc68bSmrg 
253*f0fbc68bSmrg       ((symtab_node *)data)->create_reference (vnode, IPA_REF_STORE, stmt);
254*f0fbc68bSmrg      }
255*f0fbc68bSmrg   return false;
256*f0fbc68bSmrg }
257*f0fbc68bSmrg 
258*f0fbc68bSmrg /* Record all references from cgraph_node that are taken in statement STMT.  */
259*f0fbc68bSmrg 
260*f0fbc68bSmrg void
record_stmt_references(gimple * stmt)261*f0fbc68bSmrg cgraph_node::record_stmt_references (gimple *stmt)
262*f0fbc68bSmrg {
263*f0fbc68bSmrg   walk_stmt_load_store_addr_ops (stmt, this, mark_load, mark_store,
264*f0fbc68bSmrg 				 mark_address);
265*f0fbc68bSmrg }
266*f0fbc68bSmrg 
267*f0fbc68bSmrg /* Create cgraph edges for function calls.
268*f0fbc68bSmrg    Also look for functions and variables having addresses taken.  */
269*f0fbc68bSmrg 
270*f0fbc68bSmrg namespace {
271*f0fbc68bSmrg 
272*f0fbc68bSmrg const pass_data pass_data_build_cgraph_edges =
273*f0fbc68bSmrg {
274*f0fbc68bSmrg   GIMPLE_PASS, /* type */
275*f0fbc68bSmrg   "*build_cgraph_edges", /* name */
276*f0fbc68bSmrg   OPTGROUP_NONE, /* optinfo_flags */
277*f0fbc68bSmrg   TV_NONE, /* tv_id */
278*f0fbc68bSmrg   PROP_cfg, /* properties_required */
279*f0fbc68bSmrg   0, /* properties_provided */
280*f0fbc68bSmrg   0, /* properties_destroyed */
281*f0fbc68bSmrg   0, /* todo_flags_start */
282*f0fbc68bSmrg   0, /* todo_flags_finish */
283*f0fbc68bSmrg };
284*f0fbc68bSmrg 
285*f0fbc68bSmrg class pass_build_cgraph_edges : public gimple_opt_pass
286*f0fbc68bSmrg {
287*f0fbc68bSmrg public:
pass_build_cgraph_edges(gcc::context * ctxt)288*f0fbc68bSmrg   pass_build_cgraph_edges (gcc::context *ctxt)
289*f0fbc68bSmrg     : gimple_opt_pass (pass_data_build_cgraph_edges, ctxt)
290*f0fbc68bSmrg   {}
291*f0fbc68bSmrg 
292*f0fbc68bSmrg   /* opt_pass methods: */
293*f0fbc68bSmrg   virtual unsigned int execute (function *);
294*f0fbc68bSmrg 
295*f0fbc68bSmrg }; // class pass_build_cgraph_edges
296*f0fbc68bSmrg 
297*f0fbc68bSmrg unsigned int
execute(function * fun)298*f0fbc68bSmrg pass_build_cgraph_edges::execute (function *fun)
299*f0fbc68bSmrg {
300*f0fbc68bSmrg   basic_block bb;
301*f0fbc68bSmrg   cgraph_node *node = cgraph_node::get (current_function_decl);
302*f0fbc68bSmrg   gimple_stmt_iterator gsi;
303*f0fbc68bSmrg   tree decl;
304*f0fbc68bSmrg   unsigned ix;
305*f0fbc68bSmrg 
306*f0fbc68bSmrg   /* Create the callgraph edges and record the nodes referenced by the function.
307*f0fbc68bSmrg      body.  */
308*f0fbc68bSmrg   FOR_EACH_BB_FN (bb, fun)
309*f0fbc68bSmrg     {
310*f0fbc68bSmrg       for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
311*f0fbc68bSmrg 	{
312*f0fbc68bSmrg 	  gimple *stmt = gsi_stmt (gsi);
313*f0fbc68bSmrg 	  tree decl;
314*f0fbc68bSmrg 
315*f0fbc68bSmrg 	  if (is_gimple_debug (stmt))
316*f0fbc68bSmrg 	    continue;
317*f0fbc68bSmrg 
318*f0fbc68bSmrg 	  if (gcall *call_stmt = dyn_cast <gcall *> (stmt))
319*f0fbc68bSmrg 	    {
320*f0fbc68bSmrg 	      decl = gimple_call_fndecl (call_stmt);
321*f0fbc68bSmrg 	      if (decl)
322*f0fbc68bSmrg 		node->create_edge (cgraph_node::get_create (decl), call_stmt, bb->count);
323*f0fbc68bSmrg 	      else if (gimple_call_internal_p (call_stmt))
324*f0fbc68bSmrg 		;
325*f0fbc68bSmrg 	      else
326*f0fbc68bSmrg 		node->create_indirect_edge (call_stmt,
327*f0fbc68bSmrg 					    gimple_call_flags (call_stmt),
328*f0fbc68bSmrg 					    bb->count);
329*f0fbc68bSmrg 	    }
330*f0fbc68bSmrg 	  node->record_stmt_references (stmt);
331*f0fbc68bSmrg 	  if (gomp_parallel *omp_par_stmt = dyn_cast <gomp_parallel *> (stmt))
332*f0fbc68bSmrg 	    {
333*f0fbc68bSmrg 	      tree fn = gimple_omp_parallel_child_fn (omp_par_stmt);
334*f0fbc68bSmrg 	      node->create_reference (cgraph_node::get_create (fn),
335*f0fbc68bSmrg 				      IPA_REF_ADDR, stmt);
336*f0fbc68bSmrg 	    }
337*f0fbc68bSmrg 	  if (gimple_code (stmt) == GIMPLE_OMP_TASK)
338*f0fbc68bSmrg 	    {
339*f0fbc68bSmrg 	      tree fn = gimple_omp_task_child_fn (stmt);
340*f0fbc68bSmrg 	      if (fn)
341*f0fbc68bSmrg 		node->create_reference (cgraph_node::get_create (fn),
342*f0fbc68bSmrg 					IPA_REF_ADDR, stmt);
343*f0fbc68bSmrg 	      fn = gimple_omp_task_copy_fn (stmt);
344*f0fbc68bSmrg 	      if (fn)
345*f0fbc68bSmrg 		node->create_reference (cgraph_node::get_create (fn),
346*f0fbc68bSmrg 					IPA_REF_ADDR, stmt);
347*f0fbc68bSmrg 	    }
348*f0fbc68bSmrg 	}
349*f0fbc68bSmrg       for (gsi = gsi_start_phis (bb); !gsi_end_p (gsi); gsi_next (&gsi))
350*f0fbc68bSmrg 	node->record_stmt_references (gsi_stmt (gsi));
351*f0fbc68bSmrg    }
352*f0fbc68bSmrg 
353*f0fbc68bSmrg   /* Look for initializers of constant variables and private statics.  */
354*f0fbc68bSmrg   FOR_EACH_LOCAL_DECL (fun, ix, decl)
355*f0fbc68bSmrg     if (VAR_P (decl)
356*f0fbc68bSmrg 	&& (TREE_STATIC (decl) && !DECL_EXTERNAL (decl))
357*f0fbc68bSmrg 	&& !DECL_HAS_VALUE_EXPR_P (decl)
358*f0fbc68bSmrg 	&& TREE_TYPE (decl) != error_mark_node)
359*f0fbc68bSmrg       varpool_node::finalize_decl (decl);
360*f0fbc68bSmrg   record_eh_tables (node, fun);
361*f0fbc68bSmrg 
362*f0fbc68bSmrg   return 0;
363*f0fbc68bSmrg }
364*f0fbc68bSmrg 
365*f0fbc68bSmrg } // anon namespace
366*f0fbc68bSmrg 
367*f0fbc68bSmrg gimple_opt_pass *
make_pass_build_cgraph_edges(gcc::context * ctxt)368*f0fbc68bSmrg make_pass_build_cgraph_edges (gcc::context *ctxt)
369*f0fbc68bSmrg {
370*f0fbc68bSmrg   return new pass_build_cgraph_edges (ctxt);
371*f0fbc68bSmrg }
372*f0fbc68bSmrg 
373*f0fbc68bSmrg /* Record references to functions and other variables present in the
374*f0fbc68bSmrg    initial value of DECL, a variable.
375*f0fbc68bSmrg    When ONLY_VARS is true, we mark needed only variables, not functions.  */
376*f0fbc68bSmrg 
377*f0fbc68bSmrg void
record_references_in_initializer(tree decl,bool only_vars)378*f0fbc68bSmrg record_references_in_initializer (tree decl, bool only_vars)
379*f0fbc68bSmrg {
380*f0fbc68bSmrg   varpool_node *node = varpool_node::get_create (decl);
381*f0fbc68bSmrg   hash_set<tree> visited_nodes;
382*f0fbc68bSmrg   record_reference_ctx ctx = {false, NULL};
383*f0fbc68bSmrg 
384*f0fbc68bSmrg   ctx.varpool_node = node;
385*f0fbc68bSmrg   ctx.only_vars = only_vars;
386*f0fbc68bSmrg   walk_tree (&DECL_INITIAL (decl), record_reference,
387*f0fbc68bSmrg              &ctx, &visited_nodes);
388*f0fbc68bSmrg }
389*f0fbc68bSmrg 
390*f0fbc68bSmrg /* Rebuild cgraph edges for current function node.  This needs to be run after
391*f0fbc68bSmrg    passes that don't update the cgraph.  */
392*f0fbc68bSmrg 
393*f0fbc68bSmrg unsigned int
rebuild_edges(void)394*f0fbc68bSmrg cgraph_edge::rebuild_edges (void)
395*f0fbc68bSmrg {
396*f0fbc68bSmrg   basic_block bb;
397*f0fbc68bSmrg   cgraph_node *node = cgraph_node::get (current_function_decl);
398*f0fbc68bSmrg   gimple_stmt_iterator gsi;
399*f0fbc68bSmrg 
400*f0fbc68bSmrg   node->remove_callees ();
401*f0fbc68bSmrg   node->remove_all_references ();
402*f0fbc68bSmrg 
403*f0fbc68bSmrg   node->count = ENTRY_BLOCK_PTR_FOR_FN (cfun)->count;
404*f0fbc68bSmrg 
405*f0fbc68bSmrg   FOR_EACH_BB_FN (bb, cfun)
406*f0fbc68bSmrg     {
407*f0fbc68bSmrg       for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
408*f0fbc68bSmrg 	{
409*f0fbc68bSmrg 	  gimple *stmt = gsi_stmt (gsi);
410*f0fbc68bSmrg 	  tree decl;
411*f0fbc68bSmrg 
412*f0fbc68bSmrg 	  if (gcall *call_stmt = dyn_cast <gcall *> (stmt))
413*f0fbc68bSmrg 	    {
414*f0fbc68bSmrg 	      decl = gimple_call_fndecl (call_stmt);
415*f0fbc68bSmrg 	      if (decl)
416*f0fbc68bSmrg 		node->create_edge (cgraph_node::get_create (decl), call_stmt,
417*f0fbc68bSmrg 				   bb->count);
418*f0fbc68bSmrg 	      else if (gimple_call_internal_p (call_stmt))
419*f0fbc68bSmrg 		;
420*f0fbc68bSmrg 	      else
421*f0fbc68bSmrg 		node->create_indirect_edge (call_stmt,
422*f0fbc68bSmrg 					    gimple_call_flags (call_stmt),
423*f0fbc68bSmrg 					    bb->count);
424*f0fbc68bSmrg 	    }
425*f0fbc68bSmrg 	  node->record_stmt_references (stmt);
426*f0fbc68bSmrg 	}
427*f0fbc68bSmrg       for (gsi = gsi_start_phis (bb); !gsi_end_p (gsi); gsi_next (&gsi))
428*f0fbc68bSmrg 	node->record_stmt_references (gsi_stmt (gsi));
429*f0fbc68bSmrg     }
430*f0fbc68bSmrg   record_eh_tables (node, cfun);
431*f0fbc68bSmrg   gcc_assert (!node->inlined_to);
432*f0fbc68bSmrg   return 0;
433*f0fbc68bSmrg }
434*f0fbc68bSmrg 
435*f0fbc68bSmrg /* Rebuild cgraph references for current function node.  This needs to be run
436*f0fbc68bSmrg    after passes that don't update the cgraph.  */
437*f0fbc68bSmrg 
438*f0fbc68bSmrg void
rebuild_references(void)439*f0fbc68bSmrg cgraph_edge::rebuild_references (void)
440*f0fbc68bSmrg {
441*f0fbc68bSmrg   basic_block bb;
442*f0fbc68bSmrg   cgraph_node *node = cgraph_node::get (current_function_decl);
443*f0fbc68bSmrg   gimple_stmt_iterator gsi;
444*f0fbc68bSmrg   ipa_ref *ref = NULL;
445*f0fbc68bSmrg   int i;
446*f0fbc68bSmrg 
447*f0fbc68bSmrg   /* Keep speculative references for further cgraph edge expansion.  */
448*f0fbc68bSmrg   for (i = 0; node->iterate_reference (i, ref);)
449*f0fbc68bSmrg     if (!ref->speculative)
450*f0fbc68bSmrg       ref->remove_reference ();
451*f0fbc68bSmrg     else
452*f0fbc68bSmrg       i++;
453*f0fbc68bSmrg 
454*f0fbc68bSmrg   FOR_EACH_BB_FN (bb, cfun)
455*f0fbc68bSmrg     {
456*f0fbc68bSmrg       for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
457*f0fbc68bSmrg 	node->record_stmt_references (gsi_stmt (gsi));
458*f0fbc68bSmrg       for (gsi = gsi_start_phis (bb); !gsi_end_p (gsi); gsi_next (&gsi))
459*f0fbc68bSmrg 	node->record_stmt_references (gsi_stmt (gsi));
460*f0fbc68bSmrg     }
461*f0fbc68bSmrg   record_eh_tables (node, cfun);
462*f0fbc68bSmrg }
463*f0fbc68bSmrg 
464*f0fbc68bSmrg namespace {
465*f0fbc68bSmrg 
466*f0fbc68bSmrg const pass_data pass_data_rebuild_cgraph_edges =
467*f0fbc68bSmrg {
468*f0fbc68bSmrg   GIMPLE_PASS, /* type */
469*f0fbc68bSmrg   "*rebuild_cgraph_edges", /* name */
470*f0fbc68bSmrg   OPTGROUP_NONE, /* optinfo_flags */
471*f0fbc68bSmrg   TV_CGRAPH, /* tv_id */
472*f0fbc68bSmrg   PROP_cfg, /* properties_required */
473*f0fbc68bSmrg   0, /* properties_provided */
474*f0fbc68bSmrg   0, /* properties_destroyed */
475*f0fbc68bSmrg   0, /* todo_flags_start */
476*f0fbc68bSmrg   0, /* todo_flags_finish */
477*f0fbc68bSmrg };
478*f0fbc68bSmrg 
479*f0fbc68bSmrg class pass_rebuild_cgraph_edges : public gimple_opt_pass
480*f0fbc68bSmrg {
481*f0fbc68bSmrg public:
pass_rebuild_cgraph_edges(gcc::context * ctxt)482*f0fbc68bSmrg   pass_rebuild_cgraph_edges (gcc::context *ctxt)
483*f0fbc68bSmrg     : gimple_opt_pass (pass_data_rebuild_cgraph_edges, ctxt)
484*f0fbc68bSmrg   {}
485*f0fbc68bSmrg 
486*f0fbc68bSmrg   /* opt_pass methods: */
clone()487*f0fbc68bSmrg   opt_pass * clone () { return new pass_rebuild_cgraph_edges (m_ctxt); }
execute(function *)488*f0fbc68bSmrg   virtual unsigned int execute (function *)
489*f0fbc68bSmrg   {
490*f0fbc68bSmrg     return cgraph_edge::rebuild_edges ();
491*f0fbc68bSmrg   }
492*f0fbc68bSmrg 
493*f0fbc68bSmrg }; // class pass_rebuild_cgraph_edges
494*f0fbc68bSmrg 
495*f0fbc68bSmrg } // anon namespace
496*f0fbc68bSmrg 
497*f0fbc68bSmrg gimple_opt_pass *
make_pass_rebuild_cgraph_edges(gcc::context * ctxt)498*f0fbc68bSmrg make_pass_rebuild_cgraph_edges (gcc::context *ctxt)
499*f0fbc68bSmrg {
500*f0fbc68bSmrg   return new pass_rebuild_cgraph_edges (ctxt);
501*f0fbc68bSmrg }
502*f0fbc68bSmrg 
503*f0fbc68bSmrg 
504*f0fbc68bSmrg namespace {
505*f0fbc68bSmrg 
506*f0fbc68bSmrg const pass_data pass_data_remove_cgraph_callee_edges =
507*f0fbc68bSmrg {
508*f0fbc68bSmrg   GIMPLE_PASS, /* type */
509*f0fbc68bSmrg   "*remove_cgraph_callee_edges", /* name */
510*f0fbc68bSmrg   OPTGROUP_NONE, /* optinfo_flags */
511*f0fbc68bSmrg   TV_NONE, /* tv_id */
512*f0fbc68bSmrg   0, /* properties_required */
513*f0fbc68bSmrg   0, /* properties_provided */
514*f0fbc68bSmrg   0, /* properties_destroyed */
515*f0fbc68bSmrg   0, /* todo_flags_start */
516*f0fbc68bSmrg   0, /* todo_flags_finish */
517*f0fbc68bSmrg };
518*f0fbc68bSmrg 
519*f0fbc68bSmrg class pass_remove_cgraph_callee_edges : public gimple_opt_pass
520*f0fbc68bSmrg {
521*f0fbc68bSmrg public:
pass_remove_cgraph_callee_edges(gcc::context * ctxt)522*f0fbc68bSmrg   pass_remove_cgraph_callee_edges (gcc::context *ctxt)
523*f0fbc68bSmrg     : gimple_opt_pass (pass_data_remove_cgraph_callee_edges, ctxt)
524*f0fbc68bSmrg   {}
525*f0fbc68bSmrg 
526*f0fbc68bSmrg   /* opt_pass methods: */
clone()527*f0fbc68bSmrg   opt_pass * clone () {
528*f0fbc68bSmrg     return new pass_remove_cgraph_callee_edges (m_ctxt);
529*f0fbc68bSmrg   }
530*f0fbc68bSmrg   virtual unsigned int execute (function *);
531*f0fbc68bSmrg 
532*f0fbc68bSmrg }; // class pass_remove_cgraph_callee_edges
533*f0fbc68bSmrg 
534*f0fbc68bSmrg unsigned int
execute(function *)535*f0fbc68bSmrg pass_remove_cgraph_callee_edges::execute (function *)
536*f0fbc68bSmrg {
537*f0fbc68bSmrg   cgraph_node *node = cgraph_node::get (current_function_decl);
538*f0fbc68bSmrg   node->remove_callees ();
539*f0fbc68bSmrg   node->remove_all_references ();
540*f0fbc68bSmrg   return 0;
541*f0fbc68bSmrg }
542*f0fbc68bSmrg 
543*f0fbc68bSmrg } // anon namespace
544*f0fbc68bSmrg 
545*f0fbc68bSmrg gimple_opt_pass *
make_pass_remove_cgraph_callee_edges(gcc::context * ctxt)546*f0fbc68bSmrg make_pass_remove_cgraph_callee_edges (gcc::context *ctxt)
547*f0fbc68bSmrg {
548*f0fbc68bSmrg   return new pass_remove_cgraph_callee_edges (ctxt);
549*f0fbc68bSmrg }
550