ipa.c 19 KB
Newer Older
1
/* Basic IPA optimizations and utilities.
2 3
   Copyright (C) 2003, 2004, 2005, 2007, 2008 Free Software Foundation,
   Inc.
4 5 6 7 8

This file is part of GCC.

GCC is free software; you can redistribute it and/or modify it under
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 11 12 13 14 15 16 17
version.

GCC is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
for more details.

You should have received a copy of the GNU General Public License
18 19
along with GCC; see the file COPYING3.  If not see
<http://www.gnu.org/licenses/>.  */
20 21 22 23 24 25

#include "config.h"
#include "system.h"
#include "coretypes.h"
#include "tm.h"
#include "cgraph.h"
26 27
#include "tree-pass.h"
#include "timevar.h"
28
#include "gimple.h"
29
#include "ggc.h"
30 31 32 33 34 35 36 37 38 39 40

/* Fill array order with all nodes with output flag set in the reverse
   topological order.  */

int
cgraph_postorder (struct cgraph_node **order)
{
  struct cgraph_node *node, *node2;
  int stack_size = 0;
  int order_pos = 0;
  struct cgraph_edge *edge, last;
41
  int pass;
42 43

  struct cgraph_node **stack =
44
    XCNEWVEC (struct cgraph_node *, cgraph_n_nodes);
45 46 47 48

  /* We have to deal with cycles nicely, so use a depth first traversal
     output algorithm.  Ignore the fact that some functions won't need
     to be output and put them into order as well, so we get dependencies
49
     right through inline functions.  */
50 51
  for (node = cgraph_nodes; node; node = node->next)
    node->aux = NULL;
52 53 54
  for (pass = 0; pass < 2; pass++)
    for (node = cgraph_nodes; node; node = node->next)
      if (!node->aux
55 56 57
	  && (pass
	      || (!cgraph_only_called_directly_p (node)
	  	  && !node->address_taken)))
58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93
	{
	  node2 = node;
	  if (!node->callers)
	    node->aux = &last;
	  else
	    node->aux = node->callers;
	  while (node2)
	    {
	      while (node2->aux != &last)
		{
		  edge = (struct cgraph_edge *) node2->aux;
		  if (edge->next_caller)
		    node2->aux = edge->next_caller;
		  else
		    node2->aux = &last;
		  if (!edge->caller->aux)
		    {
		      if (!edge->caller->callers)
			edge->caller->aux = &last;
		      else
			edge->caller->aux = edge->caller->callers;
		      stack[stack_size++] = node2;
		      node2 = edge->caller;
		      break;
		    }
		}
	      if (node2->aux == &last)
		{
		  order[order_pos++] = node2;
		  if (stack_size)
		    node2 = stack[--stack_size];
		  else
		    node2 = NULL;
		}
	    }
	}
94
  free (stack);
95 96
  for (node = cgraph_nodes; node; node = node->next)
    node->aux = NULL;
97 98 99
  return order_pos;
}

100 101 102 103 104 105 106 107 108 109 110 111 112 113 114
/* Look for all functions inlined to NODE and update their inlined_to pointers
   to INLINED_TO.  */

static void
update_inlined_to_pointer (struct cgraph_node *node, struct cgraph_node *inlined_to)
{
  struct cgraph_edge *e;
  for (e = node->callees; e; e = e->next_callee)
    if (e->callee->global.inlined_to)
      {
        e->callee->global.inlined_to = inlined_to;
	update_inlined_to_pointer (e->callee, inlined_to);
      }
}

115 116
/* Perform reachability analysis and reclaim all unreachable nodes.
   If BEFORE_INLINING_P is true this function is called before inlining
H.J. Lu committed
117
   decisions has been made.  If BEFORE_INLINING_P is false this function also
118 119 120
   removes unneeded bodies of extern inline functions.  */

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 127 128 129 130
  bool changed = false;

#ifdef ENABLE_CHECKING
  verify_cgraph ();
#endif
131 132
  if (file)
    fprintf (file, "\nReclaiming functions:");
133 134 135 136 137
#ifdef ENABLE_CHECKING
  for (node = cgraph_nodes; node; node = node->next)
    gcc_assert (!node->aux);
#endif
  for (node = cgraph_nodes; node; node = node->next)
138
    if (!cgraph_can_remove_if_no_direct_calls_p (node)
H.J. Lu committed
139
	&& ((!DECL_EXTERNAL (node->decl))
140 141 142
            || !node->analyzed
            || before_inlining_p))
      {
143
        gcc_assert (!node->global.inlined_to);
144 145
	node->aux = first;
	first = node;
146
	node->reachable = true;
147 148
      }
    else
149 150 151 152
      {
        gcc_assert (!node->aux);
	node->reachable = false;
      }
153 154 155 156 157 158 159 160

  /* Perform reachability analysis.  As a special case do not consider
     extern inline functions not inlined as live because we won't output
     them at all.  */
  while (first != (void *) 1)
    {
      struct cgraph_edge *e;
      node = first;
161
      first = (struct cgraph_node *) first->aux;
162
      node->aux = processed;
163

164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181
      if (node->reachable)
        for (e = node->callees; e; e = e->next_callee)
	  if (!e->callee->reachable
	      && node->analyzed
	      && (!e->inline_failed || !e->callee->analyzed
		  || (!DECL_EXTERNAL (e->callee->decl))
                  || before_inlining_p))
	    {
	      bool prev_reachable = e->callee->reachable;
	      e->callee->reachable |= node->reachable;
	      if (!e->callee->aux
	          || (e->callee->aux == processed
		      && prev_reachable != e->callee->reachable))
	        {
	          e->callee->aux = first;
	          first = e->callee;
	        }
	    }
182 183 184 185 186 187
      while (node->clone_of && !node->clone_of->aux && !gimple_has_body_p (node->decl))
        {
	  node = node->clone_of;
	  node->aux = first;
	  first = node;
	}
188 189 190 191 192 193 194 195 196 197
    }

  /* Remove unreachable nodes.  Extern inline functions need special care;
     Unreachable extern inline functions shall be removed.
     Reachable extern inline functions we never inlined shall get their bodies
     eliminated.
     Reachable extern inline functions we sometimes inlined will be turned into
     unanalyzed nodes so they look like for true extern functions to the rest
     of code.  Body of such functions is released via remove_node once the
     inline clones are eliminated.  */
198
  for (node = cgraph_nodes; node; node = next)
199
    {
200
      next = node->next;
201 202 203 204 205 206
      if (node->aux && !node->reachable)
        {
	  cgraph_node_remove_callees (node);
	  node->analyzed = false;
	  node->local.inlinable = false;
	}
207 208 209
      if (!node->aux)
	{
          node->global.inlined_to = NULL;
210 211
	  if (file)
	    fprintf (file, " %s", cgraph_node_name (node));
212
	  if (!node->analyzed || !DECL_EXTERNAL (node->decl) || before_inlining_p)
213 214 215 216 217
	    cgraph_remove_node (node);
	  else
	    {
	      struct cgraph_edge *e;

218
	      /* See if there is reachable caller.  */
219 220 221
	      for (e = node->callers; e; e = e->next_caller)
		if (e->caller->aux)
		  break;
222 223

	      /* If so, we need to keep node in the callgraph.  */
224 225 226 227
	      if (e || node->needed)
		{
		  struct cgraph_node *clone;

228 229 230 231
		  /* If there are still clones, we must keep body around.
		     Otherwise we can just remove the body but keep the clone.  */
		  for (clone = node->clones; clone;
		       clone = clone->next_sibling_clone)
232 233 234 235
		    if (clone->aux)
		      break;
		  if (!clone)
		    {
236
		      cgraph_release_function_body (node);
237
		      cgraph_node_remove_callees (node);
238
		      node->analyzed = false;
239
		      node->local.inlinable = false;
240
		    }
241 242 243 244 245 246
		  if (node->prev_sibling_clone)
		    node->prev_sibling_clone->next_sibling_clone = node->next_sibling_clone;
		  else if (node->clone_of)
		    node->clone_of->clones = node->next_sibling_clone;
		  if (node->next_sibling_clone)
		    node->next_sibling_clone->prev_sibling_clone = node->prev_sibling_clone;
247 248 249 250 251 252 253 254
		}
	      else
		cgraph_remove_node (node);
	    }
	  changed = true;
	}
    }
  for (node = cgraph_nodes; node; node = node->next)
255 256 257 258 259 260 261 262
    {
      /* Inline clones might be kept around so their materializing allows further
         cloning.  If the function the clone is inlined into is removed, we need
         to turn it into normal cone.  */
      if (node->global.inlined_to
	  && !node->callers)
	{
	  gcc_assert (node->clones);
263 264
	  node->global.inlined_to = NULL;
	  update_inlined_to_pointer (node, node);
265 266 267
	}
      node->aux = NULL;
    }
268 269 270
#ifdef ENABLE_CHECKING
  verify_cgraph ();
#endif
Diego Novillo committed
271 272 273 274 275

  /* Reclaim alias pairs for functions that have disappeared from the
     call graph.  */
  remove_unreachable_alias_pairs ();

276 277
  return changed;
}
278

279 280 281
static bool
cgraph_externally_visible_p (struct cgraph_node *node, bool whole_program)
{
282 283
  if (!node->local.finalized)
    return false;
284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300
  if (!DECL_COMDAT (node->decl)
      && (!TREE_PUBLIC (node->decl) || DECL_EXTERNAL (node->decl)))
    return false;
  if (!whole_program)
    return true;
  /* COMDAT functions must be shared only if they have address taken,
     otherwise we can produce our own private implementation with
     -fwhole-program.  */
  if (DECL_COMDAT (node->decl) && (node->address_taken || !node->analyzed))
    return true;
  if (MAIN_NAME_P (DECL_NAME (node->decl)))
    return true;
  if (lookup_attribute ("externally_visible", DECL_ATTRIBUTES (node->decl)))
    return true;
  return false;
}

301 302 303 304 305 306 307 308 309 310 311
/* Mark visibility of all functions.

   A local function is one whose calls can occur only in the current
   compilation unit and all its calls are explicit, so we can change
   its calling convention.  We simply mark all static functions whose
   address is not taken as local.

   We also change the TREE_PUBLIC flag of all declarations that are public
   in language point of view but we want to overwrite this default
   via visibilities for the backend point of view.  */

312
static unsigned int
313
function_and_variable_visibility (bool whole_program)
314 315 316 317 318 319
{
  struct cgraph_node *node;
  struct varpool_node *vnode;

  for (node = cgraph_nodes; node; node = node->next)
    {
320 321 322 323 324 325
      /* C++ FE on lack of COMDAT support create local COMDAT functions
	 (that ought to be shared but can not due to object format
	 limitations).  It is neccesary to keep the flag to make rest of C++ FE
	 happy.  Clear the flag here to avoid confusion in middle-end.  */
      if (DECL_COMDAT (node->decl) && !TREE_PUBLIC (node->decl))
        DECL_COMDAT (node->decl) = 0;
326 327
      gcc_assert ((!DECL_WEAK (node->decl) && !DECL_COMDAT (node->decl))
      	          || TREE_PUBLIC (node->decl) || DECL_EXTERNAL (node->decl));
328 329 330 331 332 333 334
      if (cgraph_externally_visible_p (node, whole_program))
        {
	  gcc_assert (!node->global.inlined_to);
	  node->local.externally_visible = true;
	}
      else
	node->local.externally_visible = false;
335 336 337
      if (!node->local.externally_visible && node->analyzed
	  && !DECL_EXTERNAL (node->decl))
	{
338
	  gcc_assert (whole_program || !TREE_PUBLIC (node->decl));
339
	  TREE_PUBLIC (node->decl) = 0;
340 341
	  DECL_COMDAT (node->decl) = 0;
	  DECL_WEAK (node->decl) = 0;
342
	}
343
      node->local.local = (cgraph_only_called_directly_p (node)
344 345 346 347 348 349
			   && node->analyzed
			   && !DECL_EXTERNAL (node->decl)
			   && !node->local.externally_visible);
    }
  for (vnode = varpool_nodes_queue; vnode; vnode = vnode->next_needed)
    {
350 351
      if (!vnode->finalized)
        continue;
352 353
      gcc_assert ((!DECL_WEAK (vnode->decl) && !DECL_COMMON (vnode->decl))
      		  || TREE_PUBLIC (vnode->decl) || DECL_EXTERNAL (vnode->decl));
354
      if (vnode->needed
355 356
	  && (DECL_COMDAT (vnode->decl) || TREE_PUBLIC (vnode->decl))
	  && (!whole_program
357 358 359 360 361
	      /* We can privatize comdat readonly variables whose address is not taken,
	         but doing so is not going to bring us optimization oppurtunities until
	         we start reordering datastructures.  */
	      || DECL_COMDAT (vnode->decl)
	      || DECL_WEAK (vnode->decl)
362 363 364 365 366
	      || lookup_attribute ("externally_visible",
				   DECL_ATTRIBUTES (vnode->decl))))
	vnode->externally_visible = true;
      else
        vnode->externally_visible = false;
367 368
      if (!vnode->externally_visible)
	{
369
	  gcc_assert (whole_program || !TREE_PUBLIC (vnode->decl));
370
	  TREE_PUBLIC (vnode->decl) = 0;
371
	  DECL_COMMON (vnode->decl) = 0;
372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387
	}
     gcc_assert (TREE_STATIC (vnode->decl));
    }

  if (dump_file)
    {
      fprintf (dump_file, "\nMarking local functions:");
      for (node = cgraph_nodes; node; node = node->next)
	if (node->local.local)
	  fprintf (dump_file, " %s", cgraph_node_name (node));
      fprintf (dump_file, "\n\n");
      fprintf (dump_file, "\nMarking externally visible functions:");
      for (node = cgraph_nodes; node; node = node->next)
	if (node->local.externally_visible)
	  fprintf (dump_file, " %s", cgraph_node_name (node));
      fprintf (dump_file, "\n\n");
388 389 390 391 392
      fprintf (dump_file, "\nMarking externally visible variables:");
      for (vnode = varpool_nodes_queue; vnode; vnode = vnode->next_needed)
	if (vnode->externally_visible)
	  fprintf (dump_file, " %s", varpool_node_name (vnode));
      fprintf (dump_file, "\n\n");
393 394
    }
  cgraph_function_flags_ready = true;
395
  return 0;
396 397
}

398 399 400 401 402 403 404 405 406
/* Local function pass handling visibilities.  This happens before LTO streaming
   so in particular -fwhole-program should be ignored at this level.  */

static unsigned int
local_function_and_variable_visibility (void)
{
  return function_and_variable_visibility (flag_whole_program && !flag_lto && !flag_whopr);
}

H.J. Lu committed
407
struct simple_ipa_opt_pass pass_ipa_function_and_variable_visibility =
408
{
409 410
 {
  SIMPLE_IPA_PASS,
411 412
  "visibility",				/* name */
  NULL,					/* gate */
413
  local_function_and_variable_visibility,/* execute */
414 415 416 417 418 419 420 421
  NULL,					/* sub */
  NULL,					/* next */
  0,					/* static_pass_number */
  TV_CGRAPHOPT,				/* tv_id */
  0,	                                /* properties_required */
  0,					/* properties_provided */
  0,					/* properties_destroyed */
  0,					/* todo_flags_start */
422 423
  TODO_remove_functions | TODO_dump_cgraph/* todo_flags_finish */
 }
424
};
425

426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444
/* Do not re-run on ltrans stage.  */

static bool
gate_whole_program_function_and_variable_visibility (void)
{
  return !flag_ltrans;
}

/* Bring functionss local at LTO time whith -fwhole-program.  */

static unsigned int
whole_program_function_and_variable_visibility (void)
{
  struct cgraph_node *node;
  struct varpool_node *vnode;

  function_and_variable_visibility (flag_whole_program);

  for (node = cgraph_nodes; node; node = node->next)
445 446
    if ((node->local.externally_visible && !DECL_COMDAT (node->decl))
        && node->local.finalized)
447 448
      cgraph_mark_needed_node (node);
  for (vnode = varpool_nodes_queue; vnode; vnode = vnode->next_needed)
449
    if (vnode->externally_visible && !DECL_COMDAT (vnode->decl))
450
      varpool_mark_needed_node (vnode);
451 452 453 454 455 456 457 458
  if (dump_file)
    {
      fprintf (dump_file, "\nNeeded variables:");
      for (vnode = varpool_nodes_queue; vnode; vnode = vnode->next_needed)
	if (vnode->needed)
	  fprintf (dump_file, " %s", varpool_node_name (vnode));
      fprintf (dump_file, "\n\n");
    }
459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482
  return 0;
}

struct ipa_opt_pass_d pass_ipa_whole_program_visibility =
{
 {
  IPA_PASS,
  "whole-program",			/* name */
  gate_whole_program_function_and_variable_visibility,/* gate */
  whole_program_function_and_variable_visibility,/* execute */
  NULL,					/* sub */
  NULL,					/* next */
  0,					/* static_pass_number */
  TV_CGRAPHOPT,				/* tv_id */
  0,	                                /* properties_required */
  0,					/* properties_provided */
  0,					/* properties_destroyed */
  0,					/* todo_flags_start */
  TODO_dump_cgraph | TODO_remove_functions/* todo_flags_finish */
 },
 NULL,					/* generate_summary */
 NULL,					/* write_summary */
 NULL,					/* read_summary */
 NULL,					/* function_read_summary */
483
 NULL,					/* stmt_fixup */
484 485 486 487
 0,					/* TODOs */
 NULL,					/* function_transform */
 NULL,					/* variable_transform */
};
488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590

/* Hash a cgraph node set element.  */

static hashval_t
hash_cgraph_node_set_element (const void *p)
{
  const_cgraph_node_set_element element = (const_cgraph_node_set_element) p;
  return htab_hash_pointer (element->node);
}

/* Compare two cgraph node set elements.  */

static int
eq_cgraph_node_set_element (const void *p1, const void *p2)
{
  const_cgraph_node_set_element e1 = (const_cgraph_node_set_element) p1;
  const_cgraph_node_set_element e2 = (const_cgraph_node_set_element) p2;

  return e1->node == e2->node;
}

/* Create a new cgraph node set.  */

cgraph_node_set
cgraph_node_set_new (void)
{
  cgraph_node_set new_node_set;

  new_node_set = GGC_NEW (struct cgraph_node_set_def);
  new_node_set->hashtab = htab_create_ggc (10,
					   hash_cgraph_node_set_element,
					   eq_cgraph_node_set_element,
					   NULL);
  new_node_set->nodes = NULL;
  return new_node_set;
}

/* Add cgraph_node NODE to cgraph_node_set SET.  */

void
cgraph_node_set_add (cgraph_node_set set, struct cgraph_node *node)
{
  void **slot;
  cgraph_node_set_element element;
  struct cgraph_node_set_element_def dummy;

  dummy.node = node;
  slot = htab_find_slot (set->hashtab, &dummy, INSERT);

  if (*slot != HTAB_EMPTY_ENTRY)
    {
      element = (cgraph_node_set_element) *slot;
      gcc_assert (node == element->node
		  && (VEC_index (cgraph_node_ptr, set->nodes, element->index)
		      == node));
      return;
    }

  /* Insert node into hash table.  */
  element =
    (cgraph_node_set_element) GGC_NEW (struct cgraph_node_set_element_def);
  element->node = node;
  element->index = VEC_length (cgraph_node_ptr, set->nodes);
  *slot = element;

  /* Insert into node vector.  */
  VEC_safe_push (cgraph_node_ptr, gc, set->nodes, node);
}

/* Remove cgraph_node NODE from cgraph_node_set SET.  */

void
cgraph_node_set_remove (cgraph_node_set set, struct cgraph_node *node)
{
  void **slot, **last_slot;
  cgraph_node_set_element element, last_element;
  struct cgraph_node *last_node;
  struct cgraph_node_set_element_def dummy;

  dummy.node = node;
  slot = htab_find_slot (set->hashtab, &dummy, NO_INSERT);
  if (slot == NULL)
    return;

  element = (cgraph_node_set_element) *slot;
  gcc_assert (VEC_index (cgraph_node_ptr, set->nodes, element->index)
	      == node);

  /* Remove from vector. We do this by swapping node with the last element
     of the vector.  */
  last_node = VEC_pop (cgraph_node_ptr, set->nodes);
  if (last_node != node)
    {
      dummy.node = last_node;
      last_slot = htab_find_slot (set->hashtab, &dummy, NO_INSERT);
      last_element = (cgraph_node_set_element) *last_slot;
      gcc_assert (last_element);

      /* Move the last element to the original spot of NODE.  */
      last_element->index = element->index;
      VEC_replace (cgraph_node_ptr, set->nodes, last_element->index,
		   last_node);
    }
H.J. Lu committed
591

592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645
  /* Remove element from hash table.  */
  htab_clear_slot (set->hashtab, slot);
  ggc_free (element);
}

/* Find NODE in SET and return an iterator to it if found.  A null iterator
   is returned if NODE is not in SET.  */

cgraph_node_set_iterator
cgraph_node_set_find (cgraph_node_set set, struct cgraph_node *node)
{
  void **slot;
  struct cgraph_node_set_element_def dummy;
  cgraph_node_set_element element;
  cgraph_node_set_iterator csi;

  dummy.node = node;
  slot = htab_find_slot (set->hashtab, &dummy, NO_INSERT);
  if (slot == NULL)
    csi.index = (unsigned) ~0;
  else
    {
      element = (cgraph_node_set_element) *slot;
      gcc_assert (VEC_index (cgraph_node_ptr, set->nodes, element->index)
		  == node);
      csi.index = element->index;
    }
  csi.set = set;

  return csi;
}

/* Dump content of SET to file F.  */

void
dump_cgraph_node_set (FILE *f, cgraph_node_set set)
{
  cgraph_node_set_iterator iter;

  for (iter = csi_start (set); !csi_end_p (iter); csi_next (&iter))
    {
      struct cgraph_node *node = csi_node (iter);
      dump_cgraph_node (f, node);
    }
}

/* Dump content of SET to stderr.  */

void
debug_cgraph_node_set (cgraph_node_set set)
{
  dump_cgraph_node_set (stderr, set);
}