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

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-dev/] [or1k-gcc/] [gcc/] [ipa-inline-transform.c] - Blame information for rev 775

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

Line No. Rev Author Line
1 684 jeremybenn
/* Callgraph transformations to handle inlining
2
   Copyright (C) 2003, 2004, 2007, 2008, 2009, 2010, 2011
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
/* The inline decisions are stored in callgraph in "inline plan" and
23
   applied later.
24
 
25
   To mark given call inline, use inline_call function.
26
   The function marks the edge inlinable and, if necessary, produces
27
   virtual clone in the callgraph representing the new copy of callee's
28
   function body.
29
 
30
   The inline plan is applied on given function body by inline_transform.  */
31
 
32
#include "config.h"
33
#include "system.h"
34
#include "coretypes.h"
35
#include "tm.h"
36
#include "tree.h"
37
#include "langhooks.h"
38
#include "cgraph.h"
39
#include "timevar.h"
40
#include "output.h"
41
#include "intl.h"
42
#include "coverage.h"
43
#include "ggc.h"
44
#include "tree-flow.h"
45
#include "ipa-prop.h"
46
#include "ipa-inline.h"
47
#include "tree-inline.h"
48
#include "tree-pass.h"
49
 
50
int ncalls_inlined;
51
int nfunctions_inlined;
52
 
53
/* Scale frequency of NODE edges by FREQ_SCALE.  */
54
 
55
static void
56
update_noncloned_frequencies (struct cgraph_node *node,
57
                              int freq_scale)
58
{
59
  struct cgraph_edge *e;
60
 
61
  /* We do not want to ignore high loop nest after freq drops to 0.  */
62
  if (!freq_scale)
63
    freq_scale = 1;
64
  for (e = node->callees; e; e = e->next_callee)
65
    {
66
      e->frequency = e->frequency * (gcov_type) freq_scale / CGRAPH_FREQ_BASE;
67
      if (e->frequency > CGRAPH_FREQ_MAX)
68
        e->frequency = CGRAPH_FREQ_MAX;
69
      if (!e->inline_failed)
70
        update_noncloned_frequencies (e->callee, freq_scale);
71
    }
72
  for (e = node->indirect_calls; e; e = e->next_callee)
73
    {
74
      e->frequency = e->frequency * (gcov_type) freq_scale / CGRAPH_FREQ_BASE;
75
      if (e->frequency > CGRAPH_FREQ_MAX)
76
        e->frequency = CGRAPH_FREQ_MAX;
77
    }
78
}
79
 
80
/* We removed or are going to remove the last call to NODE.
81
   Return true if we can and want proactively remove the NODE now.
82
   This is important to do, since we want inliner to know when offline
83
   copy of function was removed.  */
84
 
85
static bool
86
can_remove_node_now_p_1 (struct cgraph_node *node)
87
{
88
  /* FIXME: When address is taken of DECL_EXTERNAL function we still
89
     can remove its offline copy, but we would need to keep unanalyzed node in
90
     the callgraph so references can point to it.  */
91
  return (!node->address_taken
92
          && !ipa_ref_has_aliases_p (&node->ref_list)
93
          && cgraph_can_remove_if_no_direct_calls_p (node)
94
          /* Inlining might enable more devirtualizing, so we want to remove
95
             those only after all devirtualizable virtual calls are processed.
96
             Lacking may edges in callgraph we just preserve them post
97
             inlining.  */
98
          && (!DECL_VIRTUAL_P (node->decl)
99
              || (!DECL_COMDAT (node->decl)
100
                  && !DECL_EXTERNAL (node->decl)))
101
          /* During early inlining some unanalyzed cgraph nodes might be in the
102
             callgraph and they might reffer the function in question.  */
103
          && !cgraph_new_nodes);
104
}
105
 
106
/* We are going to eliminate last direct call to NODE (or alias of it) via edge E.
107
   Verify that the NODE can be removed from unit and if it is contained in comdat
108
   group that the whole comdat group is removable.  */
109
 
110
static bool
111
can_remove_node_now_p (struct cgraph_node *node, struct cgraph_edge *e)
112
{
113
  struct cgraph_node *next;
114
  if (!can_remove_node_now_p_1 (node))
115
    return false;
116
 
117
  /* When we see same comdat group, we need to be sure that all
118
     items can be removed.  */
119
  if (!node->same_comdat_group)
120
    return true;
121
  for (next = node->same_comdat_group;
122
       next != node; next = next->same_comdat_group)
123
    if ((next->callers && next->callers != e)
124
        || !can_remove_node_now_p_1 (next))
125
      return false;
126
  return true;
127
}
128
 
129
 
130
/* E is expected to be an edge being inlined.  Clone destination node of
131
   the edge and redirect it to the new clone.
132
   DUPLICATE is used for bookkeeping on whether we are actually creating new
133
   clones or re-using node originally representing out-of-line function call.
134
   */
135
 
136
void
137
clone_inlined_nodes (struct cgraph_edge *e, bool duplicate,
138
                     bool update_original, int *overall_size)
139
{
140
  if (duplicate)
141
    {
142
      /* We may eliminate the need for out-of-line copy to be output.
143
         In that case just go ahead and re-use it.  This is not just an
144
         memory optimization.  Making offline copy of fuction disappear
145
         from the program will improve future decisions on inlining.  */
146
      if (!e->callee->callers->next_caller
147
          /* Recursive inlining never wants the master clone to
148
             be overwritten.  */
149
          && update_original
150
          && can_remove_node_now_p (e->callee, e))
151
        {
152
          /* TODO: When callee is in a comdat group, we could remove all of it,
153
             including all inline clones inlined into it.  That would however
154
             need small function inlining to register edge removal hook to
155
             maintain the priority queue.
156
 
157
             For now we keep the ohter functions in the group in program until
158
             cgraph_remove_unreachable_functions gets rid of them.  */
159
          gcc_assert (!e->callee->global.inlined_to);
160
          if (e->callee->analyzed && !DECL_EXTERNAL (e->callee->decl))
161
            {
162
              if (overall_size)
163
                *overall_size -= inline_summary (e->callee)->size;
164
              nfunctions_inlined++;
165
            }
166
          duplicate = false;
167
          e->callee->local.externally_visible = false;
168
          update_noncloned_frequencies (e->callee, e->frequency);
169
        }
170
      else
171
        {
172
          struct cgraph_node *n;
173
          n = cgraph_clone_node (e->callee, e->callee->decl,
174
                                 e->count, e->frequency,
175
                                 update_original, NULL, true);
176
          cgraph_redirect_edge_callee (e, n);
177
        }
178
    }
179
 
180
  if (e->caller->global.inlined_to)
181
    e->callee->global.inlined_to = e->caller->global.inlined_to;
182
  else
183
    e->callee->global.inlined_to = e->caller;
184
 
185
  /* Recursively clone all bodies.  */
186
  for (e = e->callee->callees; e; e = e->next_callee)
187
    if (!e->inline_failed)
188
      clone_inlined_nodes (e, duplicate, update_original, overall_size);
189
}
190
 
191
 
192
/* Mark edge E as inlined and update callgraph accordingly.  UPDATE_ORIGINAL
193
   specify whether profile of original function should be updated.  If any new
194
   indirect edges are discovered in the process, add them to NEW_EDGES, unless
195
   it is NULL.  Return true iff any new callgraph edges were discovered as a
196
   result of inlining.  */
197
 
198
bool
199
inline_call (struct cgraph_edge *e, bool update_original,
200
             VEC (cgraph_edge_p, heap) **new_edges,
201
             int *overall_size)
202
{
203
  int old_size = 0, new_size = 0;
204
  struct cgraph_node *to = NULL;
205
  struct cgraph_edge *curr = e;
206
  struct cgraph_node *callee = cgraph_function_or_thunk_node (e->callee, NULL);
207
 
208
  /* Don't inline inlined edges.  */
209
  gcc_assert (e->inline_failed);
210
  /* Don't even think of inlining inline clone.  */
211
  gcc_assert (!callee->global.inlined_to);
212
 
213
  e->inline_failed = CIF_OK;
214
  DECL_POSSIBLY_INLINED (callee->decl) = true;
215
 
216
  to = e->caller;
217
  if (to->global.inlined_to)
218
    to = to->global.inlined_to;
219
 
220
  /* If aliases are involved, redirect edge to the actual destination and
221
     possibly remove the aliases.  */
222
  if (e->callee != callee)
223
    {
224
      struct cgraph_node *alias = e->callee, *next_alias;
225
      cgraph_redirect_edge_callee (e, callee);
226
      while (alias && alias != callee)
227
        {
228
          if (!alias->callers
229
              && can_remove_node_now_p (alias, e))
230
            {
231
              next_alias = cgraph_alias_aliased_node (alias);
232
              cgraph_remove_node (alias);
233
              alias = next_alias;
234
            }
235
          else
236
            break;
237
        }
238
    }
239
 
240
  clone_inlined_nodes (e, true, update_original, overall_size);
241
 
242
  gcc_assert (curr->callee->global.inlined_to == to);
243
 
244
  old_size = inline_summary (to)->size;
245
  inline_merge_summary (e);
246
  new_size = inline_summary (to)->size;
247
  if (overall_size)
248
    *overall_size += new_size - old_size;
249
  ncalls_inlined++;
250
 
251
  /* This must happen after inline_merge_summary that rely on jump
252
     functions of callee to not be updated.  */
253
  if (optimize)
254
    return ipa_propagate_indirect_call_infos (curr, new_edges);
255
  else
256
    return false;
257
}
258
 
259
 
260
/* Copy function body of NODE and redirect all inline clones to it.
261
   This is done before inline plan is applied to NODE when there are
262
   still some inline clones if it.
263
 
264
   This is neccesary because inline decisions are not really transitive
265
   and the other inline clones may have different bodies.  */
266
 
267
static struct cgraph_node *
268
save_inline_function_body (struct cgraph_node *node)
269
{
270
  struct cgraph_node *first_clone, *n;
271
 
272
  if (dump_file)
273
    fprintf (dump_file, "\nSaving body of %s for later reuse\n",
274
             cgraph_node_name (node));
275
 
276
  gcc_assert (node == cgraph_get_node (node->decl));
277
 
278
  /* first_clone will be turned into real function.  */
279
  first_clone = node->clones;
280
  first_clone->decl = copy_node (node->decl);
281
  cgraph_insert_node_to_hashtable (first_clone);
282
  gcc_assert (first_clone == cgraph_get_node (first_clone->decl));
283
 
284
  /* Now reshape the clone tree, so all other clones descends from
285
     first_clone.  */
286
  if (first_clone->next_sibling_clone)
287
    {
288
      for (n = first_clone->next_sibling_clone; n->next_sibling_clone; n = n->next_sibling_clone)
289
        n->clone_of = first_clone;
290
      n->clone_of = first_clone;
291
      n->next_sibling_clone = first_clone->clones;
292
      if (first_clone->clones)
293
        first_clone->clones->prev_sibling_clone = n;
294
      first_clone->clones = first_clone->next_sibling_clone;
295
      first_clone->next_sibling_clone->prev_sibling_clone = NULL;
296
      first_clone->next_sibling_clone = NULL;
297
      gcc_assert (!first_clone->prev_sibling_clone);
298
    }
299
  first_clone->clone_of = NULL;
300
 
301
  /* Now node in question has no clones.  */
302
  node->clones = NULL;
303
 
304
  /* Inline clones share decl with the function they are cloned
305
     from.  Walk the whole clone tree and redirect them all to the
306
     new decl.  */
307
  if (first_clone->clones)
308
    for (n = first_clone->clones; n != first_clone;)
309
      {
310
        gcc_assert (n->decl == node->decl);
311
        n->decl = first_clone->decl;
312
        if (n->clones)
313
          n = n->clones;
314
        else if (n->next_sibling_clone)
315
          n = n->next_sibling_clone;
316
        else
317
          {
318
            while (n != first_clone && !n->next_sibling_clone)
319
              n = n->clone_of;
320
            if (n != first_clone)
321
              n = n->next_sibling_clone;
322
          }
323
      }
324
 
325
  /* Copy the OLD_VERSION_NODE function tree to the new version.  */
326
  tree_function_versioning (node->decl, first_clone->decl, NULL, true, NULL,
327
                            false, NULL, NULL);
328
 
329
  /* The function will be short lived and removed after we inline all the clones,
330
     but make it internal so we won't confuse ourself.  */
331
  DECL_EXTERNAL (first_clone->decl) = 0;
332
  DECL_COMDAT_GROUP (first_clone->decl) = NULL_TREE;
333
  TREE_PUBLIC (first_clone->decl) = 0;
334
  DECL_COMDAT (first_clone->decl) = 0;
335
  VEC_free (ipa_opt_pass, heap,
336
            first_clone->ipa_transforms_to_apply);
337
  first_clone->ipa_transforms_to_apply = NULL;
338
 
339
#ifdef ENABLE_CHECKING
340
  verify_cgraph_node (first_clone);
341
#endif
342
  return first_clone;
343
}
344
 
345
 
346
/* Apply inline plan to function.  */
347
 
348
unsigned int
349
inline_transform (struct cgraph_node *node)
350
{
351
  unsigned int todo = 0;
352
  struct cgraph_edge *e;
353
 
354
  /* FIXME: Currently the pass manager is adding inline transform more than
355
     once to some clones.  This needs revisiting after WPA cleanups.  */
356
  if (cfun->after_inlining)
357
    return 0;
358
 
359
  /* We might need the body of this function so that we can expand
360
     it inline somewhere else.  */
361
  if (cgraph_preserve_function_body_p (node))
362
    save_inline_function_body (node);
363
 
364
  for (e = node->callees; e; e = e->next_callee)
365
    cgraph_redirect_edge_call_stmt_to_callee (e);
366
 
367
  timevar_push (TV_INTEGRATION);
368
  if (node->callees)
369
    todo = optimize_inline_calls (current_function_decl);
370
  timevar_pop (TV_INTEGRATION);
371
 
372
  cfun->always_inline_functions_inlined = true;
373
  cfun->after_inlining = true;
374
  todo |= execute_fixup_cfg ();
375
 
376
  if (!(todo & TODO_update_ssa_any))
377
    /* Redirecting edges might lead to a need for vops to be recomputed.  */
378
    todo |= TODO_update_ssa_only_virtuals;
379
 
380
  return todo;
381
}

powered by: WebSVN 2.1.0

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