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

Subversion Repositories openrisc

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

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

Line No. Rev Author Line
1 280 jeremybenn
/* Basic IPA optimizations and utilities.
2
   Copyright (C) 2003, 2004, 2005, 2007, 2008, 2009, 2010
3
   Free Software Foundation, Inc.
4
 
5
This file is part of GCC.
6
 
7
GCC is free software; you can redistribute it and/or modify it under
8
the terms of the GNU General Public License as published by the Free
9
Software Foundation; either version 3, or (at your option) any later
10
version.
11
 
12
GCC is distributed in the hope that it will be useful, but WITHOUT ANY
13
WARRANTY; without even the implied warranty of MERCHANTABILITY or
14
FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
15
for more details.
16
 
17
You should have received a copy of the GNU General Public License
18
along with GCC; see the file COPYING3.  If not see
19
<http://www.gnu.org/licenses/>.  */
20
 
21
#include "config.h"
22
#include "system.h"
23
#include "coretypes.h"
24
#include "tm.h"
25
#include "cgraph.h"
26
#include "tree-pass.h"
27
#include "timevar.h"
28
#include "gimple.h"
29
#include "ggc.h"
30
 
31
/* Fill array order with all nodes with output flag set in the reverse
32
   topological order.  */
33
 
34
int
35
cgraph_postorder (struct cgraph_node **order)
36
{
37
  struct cgraph_node *node, *node2;
38
  int stack_size = 0;
39
  int order_pos = 0;
40
  struct cgraph_edge *edge, last;
41
  int pass;
42
 
43
  struct cgraph_node **stack =
44
    XCNEWVEC (struct cgraph_node *, cgraph_n_nodes);
45
 
46
  /* We have to deal with cycles nicely, so use a depth first traversal
47
     output algorithm.  Ignore the fact that some functions won't need
48
     to be output and put them into order as well, so we get dependencies
49
     right through inline functions.  */
50
  for (node = cgraph_nodes; node; node = node->next)
51
    node->aux = NULL;
52
  for (pass = 0; pass < 2; pass++)
53
    for (node = cgraph_nodes; node; node = node->next)
54
      if (!node->aux
55
          && (pass
56
              || (!cgraph_only_called_directly_p (node)
57
                  && !node->address_taken)))
58
        {
59
          node2 = node;
60
          if (!node->callers)
61
            node->aux = &last;
62
          else
63
            node->aux = node->callers;
64
          while (node2)
65
            {
66
              while (node2->aux != &last)
67
                {
68
                  edge = (struct cgraph_edge *) node2->aux;
69
                  if (edge->next_caller)
70
                    node2->aux = edge->next_caller;
71
                  else
72
                    node2->aux = &last;
73
                  if (!edge->caller->aux)
74
                    {
75
                      if (!edge->caller->callers)
76
                        edge->caller->aux = &last;
77
                      else
78
                        edge->caller->aux = edge->caller->callers;
79
                      stack[stack_size++] = node2;
80
                      node2 = edge->caller;
81
                      break;
82
                    }
83
                }
84
              if (node2->aux == &last)
85
                {
86
                  order[order_pos++] = node2;
87
                  if (stack_size)
88
                    node2 = stack[--stack_size];
89
                  else
90
                    node2 = NULL;
91
                }
92
            }
93
        }
94
  free (stack);
95
  for (node = cgraph_nodes; node; node = node->next)
96
    node->aux = NULL;
97
  return order_pos;
98
}
99
 
100
/* Look for all functions inlined to NODE and update their inlined_to pointers
101
   to INLINED_TO.  */
102
 
103
static void
104
update_inlined_to_pointer (struct cgraph_node *node, struct cgraph_node *inlined_to)
105
{
106
  struct cgraph_edge *e;
107
  for (e = node->callees; e; e = e->next_callee)
108
    if (e->callee->global.inlined_to)
109
      {
110
        e->callee->global.inlined_to = inlined_to;
111
        update_inlined_to_pointer (e->callee, inlined_to);
112
      }
113
}
114
 
115
/* Perform reachability analysis and reclaim all unreachable nodes.
116
   If BEFORE_INLINING_P is true this function is called before inlining
117
   decisions has been made.  If BEFORE_INLINING_P is false this function also
118
   removes unneeded bodies of extern inline functions.  */
119
 
120
bool
121
cgraph_remove_unreachable_nodes (bool before_inlining_p, FILE *file)
122
{
123
  struct cgraph_node *first = (struct cgraph_node *) (void *) 1;
124
  struct cgraph_node *processed = (struct cgraph_node *) (void *) 2;
125
  struct cgraph_node *node, *next;
126
  bool changed = false;
127
 
128
#ifdef ENABLE_CHECKING
129
  verify_cgraph ();
130
#endif
131
  if (file)
132
    fprintf (file, "\nReclaiming functions:");
133
#ifdef ENABLE_CHECKING
134
  for (node = cgraph_nodes; node; node = node->next)
135
    gcc_assert (!node->aux);
136
#endif
137
  for (node = cgraph_nodes; node; node = node->next)
138
    if (!cgraph_can_remove_if_no_direct_calls_p (node)
139
        && ((!DECL_EXTERNAL (node->decl))
140
            || !node->analyzed
141
            || before_inlining_p))
142
      {
143
        gcc_assert (!node->global.inlined_to);
144
        node->aux = first;
145
        first = node;
146
        node->reachable = true;
147
      }
148
    else
149
      {
150
        gcc_assert (!node->aux);
151
        node->reachable = false;
152
      }
153
 
154
  /* Perform reachability analysis.  As a special case do not consider
155
     extern inline functions not inlined as live because we won't output
156
     them at all.  */
157
  while (first != (void *) 1)
158
    {
159
      struct cgraph_edge *e;
160
      node = first;
161
      first = (struct cgraph_node *) first->aux;
162
      node->aux = processed;
163
 
164
      if (node->reachable)
165
        for (e = node->callees; e; e = e->next_callee)
166
          if (!e->callee->reachable
167
              && node->analyzed
168
              && (!e->inline_failed || !e->callee->analyzed
169
                  || (!DECL_EXTERNAL (e->callee->decl))
170
                  || before_inlining_p))
171
            {
172
              bool prev_reachable = e->callee->reachable;
173
              e->callee->reachable |= node->reachable;
174
              if (!e->callee->aux
175
                  || (e->callee->aux == processed
176
                      && prev_reachable != e->callee->reachable))
177
                {
178
                  e->callee->aux = first;
179
                  first = e->callee;
180
                }
181
            }
182
 
183
      /* If any function in a comdat group is reachable, force
184
         all other functions in the same comdat group to be
185
         also reachable.  */
186
      if (node->same_comdat_group
187
          && node->reachable
188
          && !node->global.inlined_to)
189
        {
190
          for (next = node->same_comdat_group;
191
               next != node;
192
               next = next->same_comdat_group)
193
            if (!next->reachable)
194
              {
195
                next->aux = first;
196
                first = next;
197
                next->reachable = true;
198
              }
199
        }
200
 
201
      /* We can freely remove inline clones even if they are cloned, however if
202
         function is clone of real clone, we must keep it around in order to
203
         make materialize_clones produce function body with the changes
204
         applied.  */
205
      while (node->clone_of && !node->clone_of->aux && !gimple_has_body_p (node->decl))
206
        {
207
          bool noninline = node->clone_of->decl != node->decl;
208
          node = node->clone_of;
209
          if (noninline)
210
            {
211
              node->aux = first;
212
              first = node;
213
              break;
214
            }
215
        }
216
    }
217
 
218
  /* Remove unreachable nodes.  Extern inline functions need special care;
219
     Unreachable extern inline functions shall be removed.
220
     Reachable extern inline functions we never inlined shall get their bodies
221
     eliminated.
222
     Reachable extern inline functions we sometimes inlined will be turned into
223
     unanalyzed nodes so they look like for true extern functions to the rest
224
     of code.  Body of such functions is released via remove_node once the
225
     inline clones are eliminated.  */
226
  for (node = cgraph_nodes; node; node = next)
227
    {
228
      next = node->next;
229
      if (node->aux && !node->reachable)
230
        {
231
          cgraph_node_remove_callees (node);
232
          node->analyzed = false;
233
          node->local.inlinable = false;
234
        }
235
      if (!node->aux)
236
        {
237
          node->global.inlined_to = NULL;
238
          if (file)
239
            fprintf (file, " %s", cgraph_node_name (node));
240
          if (!node->analyzed || !DECL_EXTERNAL (node->decl) || before_inlining_p)
241
            cgraph_remove_node (node);
242
          else
243
            {
244
              struct cgraph_edge *e;
245
 
246
              /* See if there is reachable caller.  */
247
              for (e = node->callers; e; e = e->next_caller)
248
                if (e->caller->aux)
249
                  break;
250
 
251
              /* If so, we need to keep node in the callgraph.  */
252
              if (e || node->needed)
253
                {
254
                  struct cgraph_node *clone;
255
 
256
                  /* If there are still clones, we must keep body around.
257
                     Otherwise we can just remove the body but keep the clone.  */
258
                  for (clone = node->clones; clone;
259
                       clone = clone->next_sibling_clone)
260
                    if (clone->aux)
261
                      break;
262
                  if (!clone)
263
                    {
264
                      cgraph_release_function_body (node);
265
                      node->analyzed = false;
266
                      node->local.inlinable = false;
267
                    }
268
                  cgraph_node_remove_callees (node);
269
                  if (node->prev_sibling_clone)
270
                    node->prev_sibling_clone->next_sibling_clone = node->next_sibling_clone;
271
                  else if (node->clone_of)
272
                    node->clone_of->clones = node->next_sibling_clone;
273
                  if (node->next_sibling_clone)
274
                    node->next_sibling_clone->prev_sibling_clone = node->prev_sibling_clone;
275
                  node->clone_of = NULL;
276
                  node->next_sibling_clone = NULL;
277
                  node->prev_sibling_clone = NULL;
278
                }
279
              else
280
                cgraph_remove_node (node);
281
            }
282
          changed = true;
283
        }
284
    }
285
  for (node = cgraph_nodes; node; node = node->next)
286
    {
287
      /* Inline clones might be kept around so their materializing allows further
288
         cloning.  If the function the clone is inlined into is removed, we need
289
         to turn it into normal cone.  */
290
      if (node->global.inlined_to
291
          && !node->callers)
292
        {
293
          gcc_assert (node->clones);
294
          node->global.inlined_to = NULL;
295
          update_inlined_to_pointer (node, node);
296
        }
297
      node->aux = NULL;
298
    }
299
#ifdef ENABLE_CHECKING
300
  verify_cgraph ();
301
#endif
302
 
303
  /* Reclaim alias pairs for functions that have disappeared from the
304
     call graph.  */
305
  remove_unreachable_alias_pairs ();
306
 
307
  return changed;
308
}
309
 
310
static bool
311
cgraph_externally_visible_p (struct cgraph_node *node, bool whole_program)
312
{
313
  if (!node->local.finalized)
314
    return false;
315
  if (!DECL_COMDAT (node->decl)
316
      && (!TREE_PUBLIC (node->decl) || DECL_EXTERNAL (node->decl)))
317
    return false;
318
  if (!whole_program)
319
    return true;
320
  if (DECL_PRESERVE_P (node->decl))
321
    return true;
322
  /* COMDAT functions must be shared only if they have address taken,
323
     otherwise we can produce our own private implementation with
324
     -fwhole-program.  */
325
  if (DECL_COMDAT (node->decl))
326
    {
327
      if (node->address_taken || !node->analyzed)
328
        return true;
329
      if (node->same_comdat_group)
330
        {
331
          struct cgraph_node *next;
332
 
333
          /* If more than one function is in the same COMDAT group, it must
334
             be shared even if just one function in the comdat group has
335
             address taken.  */
336
          for (next = node->same_comdat_group;
337
               next != node;
338
               next = next->same_comdat_group)
339
            if (next->address_taken || !next->analyzed)
340
              return true;
341
        }
342
    }
343
  if (MAIN_NAME_P (DECL_NAME (node->decl)))
344
    return true;
345
  if (lookup_attribute ("externally_visible", DECL_ATTRIBUTES (node->decl)))
346
    return true;
347
  return false;
348
}
349
 
350
/* Dissolve the same_comdat_group list in which NODE resides.  */
351
 
352
static void
353
dissolve_same_comdat_group_list (struct cgraph_node *node)
354
{
355
  struct cgraph_node *n = node, *next;
356
  do
357
    {
358
      next = n->same_comdat_group;
359
      n->same_comdat_group = NULL;
360
      n = next;
361
    }
362
  while (n != node);
363
}
364
 
365
/* Mark visibility of all functions.
366
 
367
   A local function is one whose calls can occur only in the current
368
   compilation unit and all its calls are explicit, so we can change
369
   its calling convention.  We simply mark all static functions whose
370
   address is not taken as local.
371
 
372
   We also change the TREE_PUBLIC flag of all declarations that are public
373
   in language point of view but we want to overwrite this default
374
   via visibilities for the backend point of view.  */
375
 
376
static unsigned int
377
function_and_variable_visibility (bool whole_program)
378
{
379
  struct cgraph_node *node;
380
  struct varpool_node *vnode;
381
 
382
  for (node = cgraph_nodes; node; node = node->next)
383
    {
384
      /* C++ FE on lack of COMDAT support create local COMDAT functions
385
         (that ought to be shared but can not due to object format
386
         limitations).  It is neccesary to keep the flag to make rest of C++ FE
387
         happy.  Clear the flag here to avoid confusion in middle-end.  */
388
      if (DECL_COMDAT (node->decl) && !TREE_PUBLIC (node->decl))
389
        DECL_COMDAT (node->decl) = 0;
390
      /* For external decls stop tracking same_comdat_group, it doesn't matter
391
         what comdat group they are in when they won't be emitted in this TU,
392
         and simplifies later passes.  */
393
      if (node->same_comdat_group && DECL_EXTERNAL (node->decl))
394
        {
395
#ifdef ENABLE_CHECKING
396
          struct cgraph_node *n;
397
 
398
          for (n = node->same_comdat_group;
399
               n != node;
400
               n = n->same_comdat_group)
401
              /* If at least one of same comdat group functions is external,
402
                 all of them have to be, otherwise it is a front-end bug.  */
403
              gcc_assert (DECL_EXTERNAL (n->decl));
404
#endif
405
          dissolve_same_comdat_group_list (node);
406
        }
407
      gcc_assert ((!DECL_WEAK (node->decl) && !DECL_COMDAT (node->decl))
408
                  || TREE_PUBLIC (node->decl) || DECL_EXTERNAL (node->decl));
409
      if (cgraph_externally_visible_p (node, whole_program))
410
        {
411
          gcc_assert (!node->global.inlined_to);
412
          node->local.externally_visible = true;
413
        }
414
      else
415
        node->local.externally_visible = false;
416
      if (!node->local.externally_visible && node->analyzed
417
          && !DECL_EXTERNAL (node->decl))
418
        {
419
          gcc_assert (whole_program || !TREE_PUBLIC (node->decl));
420
          cgraph_make_decl_local (node->decl);
421
          if (node->same_comdat_group)
422
            /* cgraph_externally_visible_p has already checked all other nodes
423
               in the group and they will all be made local.  We need to
424
               dissolve the group at once so that the predicate does not
425
               segfault though. */
426
            dissolve_same_comdat_group_list (node);
427
        }
428
      node->local.local = (cgraph_only_called_directly_p (node)
429
                           && node->analyzed
430
                           && !DECL_EXTERNAL (node->decl)
431
                           && !node->local.externally_visible);
432
    }
433
  for (vnode = varpool_nodes; vnode; vnode = vnode->next)
434
    {
435
      /* weak flag makes no sense on local variables.  */
436
      gcc_assert (!DECL_WEAK (vnode->decl)
437
                  || TREE_PUBLIC (vnode->decl) || DECL_EXTERNAL (vnode->decl));
438
      /* In several cases declarations can not be common:
439
 
440
         - when declaration has initializer
441
         - when it is in weak
442
         - when it has specific section
443
         - when it resides in non-generic address space.
444
         - if declaration is local, it will get into .local common section
445
           so common flag is not needed.  Frontends still produce these in
446
           certain cases, such as for:
447
 
448
             static int a __attribute__ ((common))
449
 
450
         Canonicalize things here and clear the redundant flag.  */
451
      if (DECL_COMMON (vnode->decl)
452
          && (!(TREE_PUBLIC (vnode->decl) || DECL_EXTERNAL (vnode->decl))
453
              || (DECL_INITIAL (vnode->decl)
454
                  && DECL_INITIAL (vnode->decl) != error_mark_node)
455
              || DECL_WEAK (vnode->decl)
456
              || DECL_SECTION_NAME (vnode->decl) != NULL
457
              || ! (ADDR_SPACE_GENERIC_P
458
                    (TYPE_ADDR_SPACE (TREE_TYPE (vnode->decl))))))
459
        DECL_COMMON (vnode->decl) = 0;
460
    }
461
  for (vnode = varpool_nodes_queue; vnode; vnode = vnode->next_needed)
462
    {
463
      if (!vnode->finalized)
464
        continue;
465
      if (vnode->needed
466
          && (DECL_COMDAT (vnode->decl) || TREE_PUBLIC (vnode->decl))
467
          && (!whole_program
468
              /* We can privatize comdat readonly variables whose address is not taken,
469
                 but doing so is not going to bring us optimization oppurtunities until
470
                 we start reordering datastructures.  */
471
              || DECL_COMDAT (vnode->decl)
472
              || DECL_WEAK (vnode->decl)
473
              || lookup_attribute ("externally_visible",
474
                                   DECL_ATTRIBUTES (vnode->decl))))
475
        vnode->externally_visible = true;
476
      else
477
        vnode->externally_visible = false;
478
      if (!vnode->externally_visible)
479
        {
480
          gcc_assert (whole_program || !TREE_PUBLIC (vnode->decl));
481
          cgraph_make_decl_local (vnode->decl);
482
        }
483
     gcc_assert (TREE_STATIC (vnode->decl));
484
    }
485
 
486
  if (dump_file)
487
    {
488
      fprintf (dump_file, "\nMarking local functions:");
489
      for (node = cgraph_nodes; node; node = node->next)
490
        if (node->local.local)
491
          fprintf (dump_file, " %s", cgraph_node_name (node));
492
      fprintf (dump_file, "\n\n");
493
      fprintf (dump_file, "\nMarking externally visible functions:");
494
      for (node = cgraph_nodes; node; node = node->next)
495
        if (node->local.externally_visible)
496
          fprintf (dump_file, " %s", cgraph_node_name (node));
497
      fprintf (dump_file, "\n\n");
498
      fprintf (dump_file, "\nMarking externally visible variables:");
499
      for (vnode = varpool_nodes_queue; vnode; vnode = vnode->next_needed)
500
        if (vnode->externally_visible)
501
          fprintf (dump_file, " %s", varpool_node_name (vnode));
502
      fprintf (dump_file, "\n\n");
503
    }
504
  cgraph_function_flags_ready = true;
505
  return 0;
506
}
507
 
508
/* Local function pass handling visibilities.  This happens before LTO streaming
509
   so in particular -fwhole-program should be ignored at this level.  */
510
 
511
static unsigned int
512
local_function_and_variable_visibility (void)
513
{
514
  return function_and_variable_visibility (flag_whole_program && !flag_lto && !flag_whopr);
515
}
516
 
517
struct simple_ipa_opt_pass pass_ipa_function_and_variable_visibility =
518
{
519
 {
520
  SIMPLE_IPA_PASS,
521
  "visibility",                         /* name */
522
  NULL,                                 /* gate */
523
  local_function_and_variable_visibility,/* execute */
524
  NULL,                                 /* sub */
525
  NULL,                                 /* next */
526
  0,                                     /* static_pass_number */
527
  TV_CGRAPHOPT,                         /* tv_id */
528
  0,                                     /* properties_required */
529
  0,                                     /* properties_provided */
530
  0,                                     /* properties_destroyed */
531
  0,                                     /* todo_flags_start */
532
  TODO_remove_functions | TODO_dump_cgraph/* todo_flags_finish */
533
 }
534
};
535
 
536
/* Do not re-run on ltrans stage.  */
537
 
538
static bool
539
gate_whole_program_function_and_variable_visibility (void)
540
{
541
  return !flag_ltrans;
542
}
543
 
544
/* Bring functionss local at LTO time whith -fwhole-program.  */
545
 
546
static unsigned int
547
whole_program_function_and_variable_visibility (void)
548
{
549
  struct cgraph_node *node;
550
  struct varpool_node *vnode;
551
 
552
  function_and_variable_visibility (flag_whole_program);
553
 
554
  for (node = cgraph_nodes; node; node = node->next)
555
    if ((node->local.externally_visible && !DECL_COMDAT (node->decl))
556
        && node->local.finalized)
557
      cgraph_mark_needed_node (node);
558
  for (vnode = varpool_nodes_queue; vnode; vnode = vnode->next_needed)
559
    if (vnode->externally_visible && !DECL_COMDAT (vnode->decl))
560
      varpool_mark_needed_node (vnode);
561
  if (dump_file)
562
    {
563
      fprintf (dump_file, "\nNeeded variables:");
564
      for (vnode = varpool_nodes_queue; vnode; vnode = vnode->next_needed)
565
        if (vnode->needed)
566
          fprintf (dump_file, " %s", varpool_node_name (vnode));
567
      fprintf (dump_file, "\n\n");
568
    }
569
  return 0;
570
}
571
 
572
struct ipa_opt_pass_d pass_ipa_whole_program_visibility =
573
{
574
 {
575
  IPA_PASS,
576
  "whole-program",                      /* name */
577
  gate_whole_program_function_and_variable_visibility,/* gate */
578
  whole_program_function_and_variable_visibility,/* execute */
579
  NULL,                                 /* sub */
580
  NULL,                                 /* next */
581
  0,                                     /* static_pass_number */
582
  TV_CGRAPHOPT,                         /* tv_id */
583
  0,                                     /* properties_required */
584
  0,                                     /* properties_provided */
585
  0,                                     /* properties_destroyed */
586
  0,                                     /* todo_flags_start */
587
  TODO_dump_cgraph | TODO_remove_functions/* todo_flags_finish */
588
 },
589
 NULL,                                  /* generate_summary */
590
 NULL,                                  /* write_summary */
591
 NULL,                                  /* read_summary */
592
 NULL,                                  /* function_read_summary */
593
 NULL,                                  /* stmt_fixup */
594
 0,                                      /* TODOs */
595
 NULL,                                  /* function_transform */
596
 NULL,                                  /* variable_transform */
597
};
598
 
599
/* Hash a cgraph node set element.  */
600
 
601
static hashval_t
602
hash_cgraph_node_set_element (const void *p)
603
{
604
  const_cgraph_node_set_element element = (const_cgraph_node_set_element) p;
605
  return htab_hash_pointer (element->node);
606
}
607
 
608
/* Compare two cgraph node set elements.  */
609
 
610
static int
611
eq_cgraph_node_set_element (const void *p1, const void *p2)
612
{
613
  const_cgraph_node_set_element e1 = (const_cgraph_node_set_element) p1;
614
  const_cgraph_node_set_element e2 = (const_cgraph_node_set_element) p2;
615
 
616
  return e1->node == e2->node;
617
}
618
 
619
/* Create a new cgraph node set.  */
620
 
621
cgraph_node_set
622
cgraph_node_set_new (void)
623
{
624
  cgraph_node_set new_node_set;
625
 
626
  new_node_set = GGC_NEW (struct cgraph_node_set_def);
627
  new_node_set->hashtab = htab_create_ggc (10,
628
                                           hash_cgraph_node_set_element,
629
                                           eq_cgraph_node_set_element,
630
                                           NULL);
631
  new_node_set->nodes = NULL;
632
  return new_node_set;
633
}
634
 
635
/* Add cgraph_node NODE to cgraph_node_set SET.  */
636
 
637
void
638
cgraph_node_set_add (cgraph_node_set set, struct cgraph_node *node)
639
{
640
  void **slot;
641
  cgraph_node_set_element element;
642
  struct cgraph_node_set_element_def dummy;
643
 
644
  dummy.node = node;
645
  slot = htab_find_slot (set->hashtab, &dummy, INSERT);
646
 
647
  if (*slot != HTAB_EMPTY_ENTRY)
648
    {
649
      element = (cgraph_node_set_element) *slot;
650
      gcc_assert (node == element->node
651
                  && (VEC_index (cgraph_node_ptr, set->nodes, element->index)
652
                      == node));
653
      return;
654
    }
655
 
656
  /* Insert node into hash table.  */
657
  element =
658
    (cgraph_node_set_element) GGC_NEW (struct cgraph_node_set_element_def);
659
  element->node = node;
660
  element->index = VEC_length (cgraph_node_ptr, set->nodes);
661
  *slot = element;
662
 
663
  /* Insert into node vector.  */
664
  VEC_safe_push (cgraph_node_ptr, gc, set->nodes, node);
665
}
666
 
667
/* Remove cgraph_node NODE from cgraph_node_set SET.  */
668
 
669
void
670
cgraph_node_set_remove (cgraph_node_set set, struct cgraph_node *node)
671
{
672
  void **slot, **last_slot;
673
  cgraph_node_set_element element, last_element;
674
  struct cgraph_node *last_node;
675
  struct cgraph_node_set_element_def dummy;
676
 
677
  dummy.node = node;
678
  slot = htab_find_slot (set->hashtab, &dummy, NO_INSERT);
679
  if (slot == NULL)
680
    return;
681
 
682
  element = (cgraph_node_set_element) *slot;
683
  gcc_assert (VEC_index (cgraph_node_ptr, set->nodes, element->index)
684
              == node);
685
 
686
  /* Remove from vector. We do this by swapping node with the last element
687
     of the vector.  */
688
  last_node = VEC_pop (cgraph_node_ptr, set->nodes);
689
  if (last_node != node)
690
    {
691
      dummy.node = last_node;
692
      last_slot = htab_find_slot (set->hashtab, &dummy, NO_INSERT);
693
      last_element = (cgraph_node_set_element) *last_slot;
694
      gcc_assert (last_element);
695
 
696
      /* Move the last element to the original spot of NODE.  */
697
      last_element->index = element->index;
698
      VEC_replace (cgraph_node_ptr, set->nodes, last_element->index,
699
                   last_node);
700
    }
701
 
702
  /* Remove element from hash table.  */
703
  htab_clear_slot (set->hashtab, slot);
704
  ggc_free (element);
705
}
706
 
707
/* Find NODE in SET and return an iterator to it if found.  A null iterator
708
   is returned if NODE is not in SET.  */
709
 
710
cgraph_node_set_iterator
711
cgraph_node_set_find (cgraph_node_set set, struct cgraph_node *node)
712
{
713
  void **slot;
714
  struct cgraph_node_set_element_def dummy;
715
  cgraph_node_set_element element;
716
  cgraph_node_set_iterator csi;
717
 
718
  dummy.node = node;
719
  slot = htab_find_slot (set->hashtab, &dummy, NO_INSERT);
720
  if (slot == NULL)
721
    csi.index = (unsigned) ~0;
722
  else
723
    {
724
      element = (cgraph_node_set_element) *slot;
725
      gcc_assert (VEC_index (cgraph_node_ptr, set->nodes, element->index)
726
                  == node);
727
      csi.index = element->index;
728
    }
729
  csi.set = set;
730
 
731
  return csi;
732
}
733
 
734
/* Dump content of SET to file F.  */
735
 
736
void
737
dump_cgraph_node_set (FILE *f, cgraph_node_set set)
738
{
739
  cgraph_node_set_iterator iter;
740
 
741
  for (iter = csi_start (set); !csi_end_p (iter); csi_next (&iter))
742
    {
743
      struct cgraph_node *node = csi_node (iter);
744
      dump_cgraph_node (f, node);
745
    }
746
}
747
 
748
/* Dump content of SET to stderr.  */
749
 
750
void
751
debug_cgraph_node_set (cgraph_node_set set)
752
{
753
  dump_cgraph_node_set (stderr, set);
754
}
755
 

powered by: WebSVN 2.1.0

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