OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-stable/] [gcc-4.5.1/] [gcc/] [cgraphbuild.c] - Blame information for rev 847

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 280 jeremybenn
/* Callgraph construction.
2
   Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009
3
   Free Software Foundation, Inc.
4
   Contributed by Jan Hubicka
5
 
6
This file is part of GCC.
7
 
8
GCC is free software; you can redistribute it and/or modify it under
9
the terms of the GNU General Public License as published by the Free
10
Software Foundation; either version 3, or (at your option) any later
11
version.
12
 
13
GCC is distributed in the hope that it will be useful, but WITHOUT ANY
14
WARRANTY; without even the implied warranty of MERCHANTABILITY or
15
FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
16
for more details.
17
 
18
You should have received a copy of the GNU General Public License
19
along with GCC; see the file COPYING3.  If not see
20
<http://www.gnu.org/licenses/>.  */
21
 
22
#include "config.h"
23
#include "system.h"
24
#include "coretypes.h"
25
#include "tm.h"
26
#include "tree.h"
27
#include "tree-flow.h"
28
#include "langhooks.h"
29
#include "pointer-set.h"
30
#include "cgraph.h"
31
#include "intl.h"
32
#include "gimple.h"
33
#include "tree-pass.h"
34
 
35
/* Walk tree and record all calls and references to functions/variables.
36
   Called via walk_tree: TP is pointer to tree to be examined.
37
   When DATA is non-null, record references to callgraph.
38
   */
39
 
40
static tree
41
record_reference (tree *tp, int *walk_subtrees, void *data)
42
{
43
  tree t = *tp;
44
  tree decl;
45
  bool do_callgraph = data != NULL;
46
 
47
  switch (TREE_CODE (t))
48
    {
49
    case VAR_DECL:
50
      if (TREE_STATIC (t) || DECL_EXTERNAL (t))
51
        {
52
          varpool_mark_needed_node (varpool_node (t));
53
          if (lang_hooks.callgraph.analyze_expr)
54
            return lang_hooks.callgraph.analyze_expr (tp, walk_subtrees);
55
        }
56
      break;
57
 
58
    case FDESC_EXPR:
59
    case ADDR_EXPR:
60
      /* Record dereferences to the functions.  This makes the
61
         functions reachable unconditionally.  */
62
      decl = TREE_OPERAND (*tp, 0);
63
      if (TREE_CODE (decl) == FUNCTION_DECL && do_callgraph)
64
        cgraph_mark_address_taken_node (cgraph_node (decl));
65
      break;
66
 
67
    default:
68
      /* Save some cycles by not walking types and declaration as we
69
         won't find anything useful there anyway.  */
70
      if (IS_TYPE_OR_DECL_P (*tp))
71
        {
72
          *walk_subtrees = 0;
73
          break;
74
        }
75
 
76
      if ((unsigned int) TREE_CODE (t) >= LAST_AND_UNUSED_TREE_CODE)
77
        return lang_hooks.callgraph.analyze_expr (tp, walk_subtrees);
78
      break;
79
    }
80
 
81
  return NULL_TREE;
82
}
83
 
84
/* Reset inlining information of all incoming call edges of NODE.  */
85
 
86
void
87
reset_inline_failed (struct cgraph_node *node)
88
{
89
  struct cgraph_edge *e;
90
 
91
  for (e = node->callers; e; e = e->next_caller)
92
    {
93
      e->callee->global.inlined_to = NULL;
94
      if (!node->analyzed)
95
        e->inline_failed = CIF_BODY_NOT_AVAILABLE;
96
      else if (node->local.redefined_extern_inline)
97
        e->inline_failed = CIF_REDEFINED_EXTERN_INLINE;
98
      else if (!node->local.inlinable)
99
        e->inline_failed = CIF_FUNCTION_NOT_INLINABLE;
100
      else if (e->call_stmt_cannot_inline_p)
101
        e->inline_failed = CIF_MISMATCHED_ARGUMENTS;
102
      else
103
        e->inline_failed = CIF_FUNCTION_NOT_CONSIDERED;
104
    }
105
}
106
 
107
/* Computes the frequency of the call statement so that it can be stored in
108
   cgraph_edge.  BB is the basic block of the call statement.  */
109
int
110
compute_call_stmt_bb_frequency (tree decl, basic_block bb)
111
{
112
  int entry_freq = ENTRY_BLOCK_PTR_FOR_FUNCTION
113
                     (DECL_STRUCT_FUNCTION (decl))->frequency;
114
  int freq = bb->frequency;
115
 
116
  if (profile_status_for_function (DECL_STRUCT_FUNCTION (decl)) == PROFILE_ABSENT)
117
    return CGRAPH_FREQ_BASE;
118
 
119
  if (!entry_freq)
120
    entry_freq = 1, freq++;
121
 
122
  freq = freq * CGRAPH_FREQ_BASE / entry_freq;
123
  if (freq > CGRAPH_FREQ_MAX)
124
    freq = CGRAPH_FREQ_MAX;
125
 
126
  return freq;
127
}
128
 
129
/* Create cgraph edges for function calls.
130
   Also look for functions and variables having addresses taken.  */
131
 
132
static unsigned int
133
build_cgraph_edges (void)
134
{
135
  basic_block bb;
136
  struct cgraph_node *node = cgraph_node (current_function_decl);
137
  struct pointer_set_t *visited_nodes = pointer_set_create ();
138
  gimple_stmt_iterator gsi;
139
  tree step;
140
 
141
  /* Create the callgraph edges and record the nodes referenced by the function.
142
     body.  */
143
  FOR_EACH_BB (bb)
144
    for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
145
      {
146
        gimple stmt = gsi_stmt (gsi);
147
        tree decl;
148
 
149
        if (is_gimple_call (stmt) && (decl = gimple_call_fndecl (stmt)))
150
          {
151
            size_t i;
152
            size_t n = gimple_call_num_args (stmt);
153
            cgraph_create_edge (node, cgraph_node (decl), stmt,
154
                                bb->count, compute_call_stmt_bb_frequency (current_function_decl, bb),
155
                                bb->loop_depth);
156
            for (i = 0; i < n; i++)
157
              walk_tree (gimple_call_arg_ptr (stmt, i), record_reference,
158
                         node, visited_nodes);
159
            if (gimple_call_lhs (stmt))
160
              walk_tree (gimple_call_lhs_ptr (stmt), record_reference, node,
161
                         visited_nodes);
162
          }
163
        else
164
          {
165
            struct walk_stmt_info wi;
166
            memset (&wi, 0, sizeof (wi));
167
            wi.info = node;
168
            wi.pset = visited_nodes;
169
            walk_gimple_op (stmt, record_reference, &wi);
170
            if (gimple_code (stmt) == GIMPLE_OMP_PARALLEL
171
                && gimple_omp_parallel_child_fn (stmt))
172
              {
173
                tree fn = gimple_omp_parallel_child_fn (stmt);
174
                cgraph_mark_needed_node (cgraph_node (fn));
175
              }
176
            if (gimple_code (stmt) == GIMPLE_OMP_TASK)
177
              {
178
                tree fn = gimple_omp_task_child_fn (stmt);
179
                if (fn)
180
                  cgraph_mark_needed_node (cgraph_node (fn));
181
                fn = gimple_omp_task_copy_fn (stmt);
182
                if (fn)
183
                  cgraph_mark_needed_node (cgraph_node (fn));
184
              }
185
          }
186
      }
187
 
188
  /* Look for initializers of constant variables and private statics.  */
189
  for (step = cfun->local_decls;
190
       step;
191
       step = TREE_CHAIN (step))
192
    {
193
      tree decl = TREE_VALUE (step);
194
      if (TREE_CODE (decl) == VAR_DECL
195
          && (TREE_STATIC (decl) && !DECL_EXTERNAL (decl)))
196
        varpool_finalize_decl (decl);
197
      else if (TREE_CODE (decl) == VAR_DECL && DECL_INITIAL (decl))
198
        walk_tree (&DECL_INITIAL (decl), record_reference, node, visited_nodes);
199
    }
200
 
201
  pointer_set_destroy (visited_nodes);
202
  return 0;
203
}
204
 
205
struct gimple_opt_pass pass_build_cgraph_edges =
206
{
207
 {
208
  GIMPLE_PASS,
209
  "*build_cgraph_edges",                        /* name */
210
  NULL,                                 /* gate */
211
  build_cgraph_edges,                   /* execute */
212
  NULL,                                 /* sub */
213
  NULL,                                 /* next */
214
  0,                                     /* static_pass_number */
215
  TV_NONE,                              /* tv_id */
216
  PROP_cfg,                             /* properties_required */
217
  0,                                     /* properties_provided */
218
  0,                                     /* properties_destroyed */
219
  0,                                     /* todo_flags_start */
220
 
221
 }
222
};
223
 
224
/* Record references to functions and other variables present in the
225
   initial value of DECL, a variable.
226
   When ONLY_VARS is true, we mark needed only variables, not functions.  */
227
 
228
void
229
record_references_in_initializer (tree decl, bool only_vars)
230
{
231
  struct pointer_set_t *visited_nodes = pointer_set_create ();
232
  walk_tree (&DECL_INITIAL (decl), record_reference,
233
            only_vars ? NULL : decl, visited_nodes);
234
  pointer_set_destroy (visited_nodes);
235
}
236
 
237
/* Rebuild cgraph edges for current function node.  This needs to be run after
238
   passes that don't update the cgraph.  */
239
 
240
unsigned int
241
rebuild_cgraph_edges (void)
242
{
243
  basic_block bb;
244
  struct cgraph_node *node = cgraph_node (current_function_decl);
245
  gimple_stmt_iterator gsi;
246
 
247
  cgraph_node_remove_callees (node);
248
 
249
  node->count = ENTRY_BLOCK_PTR->count;
250
 
251
  FOR_EACH_BB (bb)
252
    for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
253
      {
254
        gimple stmt = gsi_stmt (gsi);
255
        tree decl;
256
 
257
        if (is_gimple_call (stmt) && (decl = gimple_call_fndecl (stmt)))
258
          cgraph_create_edge (node, cgraph_node (decl), stmt,
259
                              bb->count,
260
                              compute_call_stmt_bb_frequency
261
                                (current_function_decl, bb),
262
                              bb->loop_depth);
263
 
264
      }
265
  gcc_assert (!node->global.inlined_to);
266
 
267
  return 0;
268
}
269
 
270
struct gimple_opt_pass pass_rebuild_cgraph_edges =
271
{
272
 {
273
  GIMPLE_PASS,
274
  "*rebuild_cgraph_edges",              /* name */
275
  NULL,                                 /* gate */
276
  rebuild_cgraph_edges,                 /* execute */
277
  NULL,                                 /* sub */
278
  NULL,                                 /* next */
279
  0,                                     /* static_pass_number */
280
  TV_NONE,                              /* tv_id */
281
  PROP_cfg,                             /* properties_required */
282
  0,                                     /* properties_provided */
283
  0,                                     /* properties_destroyed */
284
  0,                                     /* todo_flags_start */
285
  0,                                     /* todo_flags_finish */
286
 }
287
};
288
 
289
 
290
static unsigned int
291
remove_cgraph_callee_edges (void)
292
{
293
  cgraph_node_remove_callees (cgraph_node (current_function_decl));
294
  return 0;
295
}
296
 
297
struct gimple_opt_pass pass_remove_cgraph_callee_edges =
298
{
299
 {
300
  GIMPLE_PASS,
301
  "*remove_cgraph_callee_edges",                /* name */
302
  NULL,                                 /* gate */
303
  remove_cgraph_callee_edges,           /* execute */
304
  NULL,                                 /* sub */
305
  NULL,                                 /* next */
306
  0,                                     /* static_pass_number */
307
  TV_NONE,                              /* tv_id */
308
  0,                                     /* properties_required */
309
  0,                                     /* properties_provided */
310
  0,                                     /* properties_destroyed */
311
  0,                                     /* todo_flags_start */
312
  0,                                     /* todo_flags_finish */
313
 }
314
};

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.