ipa-cp.c 104 KB
Newer Older
Razya Ladelsky committed
1
/* Interprocedural constant propagation
2
   Copyright (C) 2005-2013 Free Software Foundation, Inc.
3 4 5

   Contributed by Razya Ladelsky <RAZYA@il.ibm.com> and Martin Jambor
   <mjambor@suse.cz>
H.J. Lu committed
6

Razya Ladelsky committed
7
This file is part of GCC.
H.J. Lu committed
8

Razya Ladelsky committed
9 10
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
11
Software Foundation; either version 3, or (at your option) any later
Razya Ladelsky committed
12
version.
H.J. Lu committed
13

Razya Ladelsky committed
14 15 16 17
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.
H.J. Lu committed
18

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

23
/* Interprocedural constant propagation (IPA-CP).
H.J. Lu committed
24

25
   The goal of this transformation is to
26

27 28 29
   1) discover functions which are always invoked with some arguments with the
      same known constant values and modify the functions so that the
      subsequent optimizations can take advantage of the knowledge, and
30

31 32 33 34
   2) partial specialization - create specialized versions of functions
      transformed in this way if some parameters are known constants only in
      certain contexts but the estimated tradeoff between speedup and cost size
      is deemed good.
H.J. Lu committed
35

36 37
   The algorithm also propagates types and attempts to perform type based
   devirtualization.  Types are propagated much like constants.
H.J. Lu committed
38

39 40 41 42 43 44 45 46
   The algorithm basically consists of three stages.  In the first, functions
   are analyzed one at a time and jump functions are constructed for all known
   call-sites.  In the second phase, the pass propagates information from the
   jump functions across the call to reveal what values are available at what
   call sites, performs estimations of effects of known values on functions and
   their callees, and finally decides what specialized extra versions should be
   created.  In the third, the special versions materialize and appropriate
   calls are redirected.
47

48 49 50 51
   The algorithm used is to a certain extent based on "Interprocedural Constant
   Propagation", by David Callahan, Keith D Cooper, Ken Kennedy, Linda Torczon,
   Comp86, pg 152-161 and "A Methodology for Procedure Cloning" by Keith D
   Cooper, Mary W. Hall, and Ken Kennedy.
H.J. Lu committed
52

Razya Ladelsky committed
53 54 55

   First stage - intraprocedural analysis
   =======================================
56

57
   This phase computes jump_function and modification flags.
H.J. Lu committed
58

59 60 61 62 63 64
   A jump function for a call-site represents the values passed as an actual
   arguments of a given call-site. In principle, there are three types of
   values:

   Pass through - the caller's formal parameter is passed as an actual
                  argument, plus an operation on it can be performed.
65
   Constant - a constant is passed as an actual argument.
Razya Ladelsky committed
66
   Unknown - neither of the above.
H.J. Lu committed
67

68 69
   All jump function types are described in detail in ipa-prop.h, together with
   the data structures that represent them and methods of accessing them.
H.J. Lu committed
70

71
   ipcp_generate_summary() is the main function of the first stage.
Razya Ladelsky committed
72 73 74

   Second stage - interprocedural analysis
   ========================================
H.J. Lu committed
75

76 77 78
   This stage is itself divided into two phases.  In the first, we propagate
   known values over the call graph, in the second, we make cloning decisions.
   It uses a different algorithm than the original Callahan's paper.
H.J. Lu committed
79

80 81 82 83
   First, we traverse the functions topologically from callers to callees and,
   for each strongly connected component (SCC), we propagate constants
   according to previously computed jump functions.  We also record what known
   values depend on other known values and estimate local effects.  Finally, we
Joseph Myers committed
84
   propagate cumulative information about these effects from dependent values
85
   to those on which they depend.
Razya Ladelsky committed
86

87 88 89 90 91
   Second, we again traverse the call graph in the same topological order and
   make clones for functions which we know are called with the same values in
   all contexts and decide about extra specialized clones of functions just for
   some contexts - these decisions are based on both local estimates and
   cumulative estimates propagated from callees.
Razya Ladelsky committed
92

93 94 95 96
   ipcp_propagate_stage() and ipcp_decision_stage() together constitute the
   third stage.

   Third phase - materialization of clones, call statement updates.
Razya Ladelsky committed
97
   ============================================
98 99 100 101

   This stage is currently performed by call graph code (mainly in cgraphunit.c
   and tree-inline.c) according to instructions inserted to the call graph by
   the second stage.  */
Razya Ladelsky committed
102 103 104 105 106 107

#include "config.h"
#include "system.h"
#include "coretypes.h"
#include "tree.h"
#include "target.h"
108
#include "gimple.h"
Razya Ladelsky committed
109 110 111 112 113 114
#include "cgraph.h"
#include "ipa-prop.h"
#include "tree-flow.h"
#include "tree-pass.h"
#include "flags.h"
#include "diagnostic.h"
115
#include "tree-pretty-print.h"
116
#include "tree-inline.h"
117
#include "params.h"
118
#include "ipa-inline.h"
119
#include "ipa-utils.h"
Razya Ladelsky committed
120

121
struct ipcp_value;
122

123
/* Describes a particular source for an IPA-CP value.  */
124

125 126
struct ipcp_value_source
{
127 128 129
  /* Aggregate offset of the source, negative if the source is scalar value of
     the argument itself.  */
  HOST_WIDE_INT offset;
130 131 132 133 134 135 136 137 138 139 140 141 142
  /* The incoming edge that brought the value.  */
  struct cgraph_edge *cs;
  /* If the jump function that resulted into his value was a pass-through or an
     ancestor, this is the ipcp_value of the caller from which the described
     value has been derived.  Otherwise it is NULL.  */
  struct ipcp_value *val;
  /* Next pointer in a linked list of sources of a value.  */
  struct ipcp_value_source *next;
  /* If the jump function that resulted into his value was a pass-through or an
     ancestor, this is the index of the parameter of the caller the jump
     function references.  */
  int index;
};
143

144
/* Describes one particular value stored in struct ipcp_lattice.  */
145

146
struct ipcp_value
Razya Ladelsky committed
147
{
148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176
  /* The actual value for the given parameter.  This is either an IPA invariant
     or a TREE_BINFO describing a type that can be used for
     devirtualization.  */
  tree value;
  /* The list of sources from which this value originates.  */
  struct ipcp_value_source *sources;
  /* Next pointers in a linked list of all values in a lattice.  */
  struct ipcp_value *next;
  /* Next pointers in a linked list of values in a strongly connected component
     of values. */
  struct ipcp_value *scc_next;
  /* Next pointers in a linked list of SCCs of values sorted topologically
     according their sources.  */
  struct ipcp_value  *topo_next;
  /* A specialized node created for this value, NULL if none has been (so far)
     created.  */
  struct cgraph_node *spec_node;
  /* Depth first search number and low link for topological sorting of
     values.  */
  int dfs, low_link;
  /* Time benefit and size cost that specializing the function for this value
     would bring about in this function alone.  */
  int local_time_benefit, local_size_cost;
  /* Time benefit and size cost that specializing the function for this value
     can bring about in it's callees (transitively).  */
  int prop_time_benefit, prop_size_cost;
  /* True if this valye is currently on the topo-sort stack.  */
  bool on_stack;
};
Razya Ladelsky committed
177

178 179 180 181
/* Lattice describing potential values of a formal parameter of a function, or
   a part of an aggreagate.  TOP is represented by a lattice with zero values
   and with contains_variable and bottom flags cleared.  BOTTOM is represented
   by a lattice with the bottom flag set.  In that case, values and
182 183 184
   contains_variable flag should be disregarded.  */

struct ipcp_lattice
Razya Ladelsky committed
185
{
186 187 188 189 190 191
  /* The list of known values and types in this lattice.  Note that values are
     not deallocated if a lattice is set to bottom because there may be value
     sources referencing them.  */
  struct ipcp_value *values;
  /* Number of known values and types in this lattice.  */
  int values_count;
192
  /* The lattice contains a variable component (in addition to values).  */
193 194 195 196
  bool contains_variable;
  /* The value of the lattice is bottom (i.e. variable and unusable for any
     propagation).  */
  bool bottom;
197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233
};

/* Lattice with an offset to describe a part of an aggregate.  */

struct ipcp_agg_lattice : public ipcp_lattice
{
  /* Offset that is being described by this lattice. */
  HOST_WIDE_INT offset;
  /* Size so that we don't have to re-compute it every time we traverse the
     list.  Must correspond to TYPE_SIZE of all lat values.  */
  HOST_WIDE_INT size;
  /* Next element of the linked list.  */
  struct ipcp_agg_lattice *next;
};

/* Structure containing lattices for a parameter itself and for pieces of
   aggregates that are passed in the parameter or by a reference in a parameter
   plus some other useful flags.  */

struct ipcp_param_lattices
{
  /* Lattice describing the value of the parameter itself.  */
  struct ipcp_lattice itself;
  /* Lattices describing aggregate parts.  */
  struct ipcp_agg_lattice *aggs;
  /* Number of aggregate lattices */
  int aggs_count;
  /* True if aggregate data were passed by reference (as opposed to by
     value).  */
  bool aggs_by_ref;
  /* All aggregate lattices contain a variable component (in addition to
     values).  */
  bool aggs_contain_variable;
  /* The value of all aggregate lattices is bottom (i.e. variable and unusable
     for any propagation).  */
  bool aggs_bottom;

234 235 236
  /* There is a virtual call based on this parameter.  */
  bool virt_call;
};
Razya Ladelsky committed
237

238 239 240 241 242 243
/* Allocation pools for values and their sources in ipa-cp.  */

alloc_pool ipcp_values_pool;
alloc_pool ipcp_sources_pool;
alloc_pool ipcp_agg_lattice_pool;

244 245 246 247 248 249 250 251 252 253 254 255
/* Maximal count found in program.  */

static gcov_type max_count;

/* Original overall size of the program.  */

static long overall_size, max_new_size;

/* Head of the linked list of topologically sorted values. */

static struct ipcp_value *values_topo;

256 257 258 259
/* Return the param lattices structure corresponding to the Ith formal
   parameter of the function described by INFO.  */
static inline struct ipcp_param_lattices *
ipa_get_parm_lattices (struct ipa_node_params *info, int i)
Razya Ladelsky committed
260
{
261
  gcc_assert (i >= 0 && i < ipa_get_param_count (info));
262 263 264
  gcc_checking_assert (!info->ipcp_orig_node);
  gcc_checking_assert (info->lattices);
  return &(info->lattices[i]);
Razya Ladelsky committed
265 266
}

267 268 269 270 271 272 273 274 275
/* Return the lattice corresponding to the scalar value of the Ith formal
   parameter of the function described by INFO.  */
static inline struct ipcp_lattice *
ipa_get_scalar_lat (struct ipa_node_params *info, int i)
{
  struct ipcp_param_lattices *plats = ipa_get_parm_lattices (info, i);
  return &plats->itself;
}

276 277 278
/* Return whether LAT is a lattice with a single constant and without an
   undefined value.  */

279
static inline bool
280
ipa_lat_is_single_const (struct ipcp_lattice *lat)
Razya Ladelsky committed
281
{
282 283 284
  if (lat->bottom
      || lat->contains_variable
      || lat->values_count != 1)
Razya Ladelsky committed
285
    return false;
286 287
  else
    return true;
Razya Ladelsky committed
288 289
}

290 291
/* Return true iff the CS is an edge within a strongly connected component as
   computed by ipa_reduced_postorder.  */
292

Razya Ladelsky committed
293
static inline bool
294
edge_within_scc (struct cgraph_edge *cs)
Razya Ladelsky committed
295
{
296
  struct ipa_dfs_info *caller_dfs = (struct ipa_dfs_info *) cs->caller->symbol.aux;
297 298 299
  struct ipa_dfs_info *callee_dfs;
  struct cgraph_node *callee = cgraph_function_node (cs->callee, NULL);

300
  callee_dfs = (struct ipa_dfs_info *) callee->symbol.aux;
301 302 303
  return (caller_dfs
	  && callee_dfs
	  && caller_dfs->scc_no == callee_dfs->scc_no);
Razya Ladelsky committed
304 305
}

306 307
/* Print V which is extracted from a value in a lattice to F.  */

Razya Ladelsky committed
308
static void
309
print_ipcp_constant_value (FILE * f, tree v)
Razya Ladelsky committed
310
{
311
  if (TREE_CODE (v) == TREE_BINFO)
Razya Ladelsky committed
312
    {
313 314
      fprintf (f, "BINFO ");
      print_generic_expr (f, BINFO_TYPE (v), 0);
Razya Ladelsky committed
315
    }
316 317
  else if (TREE_CODE (v) == ADDR_EXPR
	   && TREE_CODE (TREE_OPERAND (v, 0)) == CONST_DECL)
Razya Ladelsky committed
318
    {
319 320
      fprintf (f, "& ");
      print_generic_expr (f, DECL_INITIAL (TREE_OPERAND (v, 0)), 0);
Razya Ladelsky committed
321
    }
322 323
  else
    print_generic_expr (f, v, 0);
Razya Ladelsky committed
324 325
}

326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385
/* Print a lattice LAT to F.  */

static void
print_lattice (FILE * f, struct ipcp_lattice *lat,
	       bool dump_sources, bool dump_benefits)
{
  struct ipcp_value *val;
  bool prev = false;

  if (lat->bottom)
    {
      fprintf (f, "BOTTOM\n");
      return;
    }

  if (!lat->values_count && !lat->contains_variable)
    {
      fprintf (f, "TOP\n");
      return;
    }

  if (lat->contains_variable)
    {
      fprintf (f, "VARIABLE");
      prev = true;
      if (dump_benefits)
	fprintf (f, "\n");
    }

  for (val = lat->values; val; val = val->next)
    {
      if (dump_benefits && prev)
	fprintf (f, "               ");
      else if (!dump_benefits && prev)
	fprintf (f, ", ");
      else
	prev = true;

      print_ipcp_constant_value (f, val->value);

      if (dump_sources)
	{
	  struct ipcp_value_source *s;

	  fprintf (f, " [from:");
	  for (s = val->sources; s; s = s->next)
	    fprintf (f, " %i(%i)", s->cs->caller->uid,s->cs->frequency);
	  fprintf (f, "]");
	}

      if (dump_benefits)
	fprintf (f, " [loc_time: %i, loc_size: %i, "
		 "prop_time: %i, prop_size: %i]\n",
		 val->local_time_benefit, val->local_size_cost,
		 val->prop_time_benefit, val->prop_size_cost);
    }
  if (!dump_benefits)
    fprintf (f, "\n");
}

386
/* Print all ipcp_lattices of all functions to F.  */
387

Razya Ladelsky committed
388
static void
389
print_all_lattices (FILE * f, bool dump_sources, bool dump_benefits)
Razya Ladelsky committed
390 391 392
{
  struct cgraph_node *node;
  int i, count;
393

394 395
  fprintf (f, "\nLattices:\n");
  FOR_EACH_FUNCTION_WITH_GIMPLE_BODY (node)
Razya Ladelsky committed
396
    {
397 398 399
      struct ipa_node_params *info;

      info = IPA_NODE_REF (node);
400
      fprintf (f, "  Node: %s/%i:\n", cgraph_node_name (node), node->uid);
401
      count = ipa_get_param_count (info);
Razya Ladelsky committed
402 403
      for (i = 0; i < count; i++)
	{
404 405
	  struct ipcp_agg_lattice *aglat;
	  struct ipcp_param_lattices *plats = ipa_get_parm_lattices (info, i);
406
	  fprintf (f, "    param [%d]: ", i);
407
	  print_lattice (f, &plats->itself, dump_sources, dump_benefits);
408

409 410 411 412
	  if (plats->virt_call)
	    fprintf (f, "        virt_call flag set\n");

	  if (plats->aggs_bottom)
413
	    {
414
	      fprintf (f, "        AGGS BOTTOM\n");
415 416
	      continue;
	    }
417 418 419
	  if (plats->aggs_contain_variable)
	    fprintf (f, "        AGGS VARIABLE\n");
	  for (aglat = plats->aggs; aglat; aglat = aglat->next)
420
	    {
421 422 423
	      fprintf (f, "        %soffset " HOST_WIDE_INT_PRINT_DEC ": ",
		       plats->aggs_by_ref ? "ref " : "", aglat->offset);
	      print_lattice (f, aglat, dump_sources, dump_benefits);
424
	    }
Razya Ladelsky committed
425 426 427 428
	}
    }
}

429 430 431
/* Determine whether it is at all technically possible to create clones of NODE
   and store this information in the ipa_node_params structure associated
   with NODE.  */
432

433 434
static void
determine_versionability (struct cgraph_node *node)
435
{
436
  const char *reason = NULL;
437

438 439 440
  /* There are a number of generic reasons functions cannot be versioned.  We
     also cannot remove parameters if there are type attributes such as fnspec
     present.  */
441 442
  if (node->alias || node->thunk.thunk_p)
    reason = "alias or thunk";
443
  else if (!node->local.versionable)
444
    reason = "not a tree_versionable_function";
445 446
  else if (cgraph_function_body_availability (node) <= AVAIL_OVERWRITABLE)
    reason = "insufficient body availability";
447

448 449 450
  if (reason && dump_file && !node->alias && !node->thunk.thunk_p)
    fprintf (dump_file, "Function %s/%i is not versionable, reason: %s.\n",
	     cgraph_node_name (node), node->uid, reason);
451

452
  node->local.versionable = (reason == NULL);
453 454
}

455 456 457
/* Return true if it is at all technically possible to create clones of a
   NODE.  */

458
static bool
459
ipcp_versionable_function_p (struct cgraph_node *node)
460
{
461
  return node->local.versionable;
462
}
463

464
/* Structure holding accumulated information about callers of a node.  */
465

466 467 468 469 470
struct caller_statistics
{
  gcov_type count_sum;
  int n_calls, n_hot_calls, freq_sum;
};
471

472
/* Initialize fields of STAT to zeroes.  */
473

474 475 476 477 478 479 480 481 482 483 484 485 486 487 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
static inline void
init_caller_stats (struct caller_statistics *stats)
{
  stats->count_sum = 0;
  stats->n_calls = 0;
  stats->n_hot_calls = 0;
  stats->freq_sum = 0;
}

/* Worker callback of cgraph_for_node_and_aliases accumulating statistics of
   non-thunk incoming edges to NODE.  */

static bool
gather_caller_stats (struct cgraph_node *node, void *data)
{
  struct caller_statistics *stats = (struct caller_statistics *) data;
  struct cgraph_edge *cs;

  for (cs = node->callers; cs; cs = cs->next_caller)
    if (cs->caller->thunk.thunk_p)
      cgraph_for_node_and_aliases (cs->caller, gather_caller_stats,
				   stats, false);
    else
      {
	stats->count_sum += cs->count;
	stats->freq_sum += cs->frequency;
	stats->n_calls++;
	if (cgraph_maybe_hot_edge_p (cs))
	  stats->n_hot_calls ++;
      }
  return false;

}

/* Return true if this NODE is viable candidate for cloning.  */

static bool
ipcp_cloning_candidate_p (struct cgraph_node *node)
{
  struct caller_statistics stats;

  gcc_checking_assert (cgraph_function_with_gimple_body_p (node));
H.J. Lu committed
516

517
  if (!flag_ipa_cp_clone)
518 519
    {
      if (dump_file)
520 521
        fprintf (dump_file, "Not considering %s for cloning; "
		 "-fipa-cp-clone disabled.\n",
522 523 524 525
 	         cgraph_node_name (node));
      return false;
    }

526
  if (!optimize_function_for_speed_p (DECL_STRUCT_FUNCTION (node->symbol.decl)))
527 528
    {
      if (dump_file)
529 530
        fprintf (dump_file, "Not considering %s for cloning; "
		 "optimizing it for size.\n",
531 532 533 534
 	         cgraph_node_name (node));
      return false;
    }

535 536 537 538
  init_caller_stats (&stats);
  cgraph_for_node_and_aliases (node, gather_caller_stats, &stats, false);

  if (inline_summary (node)->self_size < stats.n_calls)
539 540
    {
      if (dump_file)
541
        fprintf (dump_file, "Considering %s for cloning; code might shrink.\n",
542
 	         cgraph_node_name (node));
543
      return true;
544 545 546 547
    }

  /* When profile is available and function is hot, propagate into it even if
     calls seems cold; constant propagation can improve function's speed
548
     significantly.  */
549 550
  if (max_count)
    {
551
      if (stats.count_sum > node->count * 90 / 100)
552 553
	{
	  if (dump_file)
554 555
	    fprintf (dump_file, "Considering %s for cloning; "
		     "usually called directly.\n",
556 557 558 559
		     cgraph_node_name (node));
	  return true;
        }
    }
560
  if (!stats.n_hot_calls)
561 562 563 564
    {
      if (dump_file)
	fprintf (dump_file, "Not considering %s for cloning; no hot calls.\n",
		 cgraph_node_name (node));
565
      return false;
566 567 568 569 570 571 572
    }
  if (dump_file)
    fprintf (dump_file, "Considering %s for cloning.\n",
	     cgraph_node_name (node));
  return true;
}

573 574
/* Arrays representing a topological ordering of call graph nodes and a stack
   of noes used during constant propagation.  */
575

576
struct topo_info
577
{
578 579 580 581 582 583 584 585 586 587 588 589 590 591
  struct cgraph_node **order;
  struct cgraph_node **stack;
  int nnodes, stack_top;
};

/* Allocate the arrays in TOPO and topologically sort the nodes into order.  */

static void
build_toporder_info (struct topo_info *topo)
{
  topo->order = XCNEWVEC (struct cgraph_node *, cgraph_n_nodes);
  topo->stack = XCNEWVEC (struct cgraph_node *, cgraph_n_nodes);
  topo->stack_top = 0;
  topo->nnodes = ipa_reduced_postorder (topo->order, true, true, NULL);
592 593
}

594 595 596
/* Free information about strongly connected components and the arrays in
   TOPO.  */

Razya Ladelsky committed
597
static void
598 599 600 601 602 603 604 605 606 607 608
free_toporder_info (struct topo_info *topo)
{
  ipa_free_postorder_info ();
  free (topo->order);
  free (topo->stack);
}

/* Add NODE to the stack in TOPO, unless it is already there.  */

static inline void
push_node_to_stack (struct topo_info *topo, struct cgraph_node *node)
Razya Ladelsky committed
609
{
610
  struct ipa_node_params *info = IPA_NODE_REF (node);
611 612 613 614 615
  if (info->node_enqueued)
    return;
  info->node_enqueued = 1;
  topo->stack[topo->stack_top++] = node;
}
Razya Ladelsky committed
616

617 618
/* Pop a node from the stack in TOPO and return it or return NULL if the stack
   is empty.  */
619

620 621 622 623
static struct cgraph_node *
pop_node_from_stack (struct topo_info *topo)
{
  if (topo->stack_top)
624
    {
625 626 627 628 629
      struct cgraph_node *node;
      topo->stack_top--;
      node = topo->stack[topo->stack_top];
      IPA_NODE_REF (node)->node_enqueued = 0;
      return node;
630
    }
631 632
  else
    return NULL;
Razya Ladelsky committed
633 634
}

635 636 637 638 639
/* Set lattice LAT to bottom and return true if it previously was not set as
   such.  */

static inline bool
set_lattice_to_bottom (struct ipcp_lattice *lat)
Razya Ladelsky committed
640
{
641 642 643 644
  bool ret = !lat->bottom;
  lat->bottom = true;
  return ret;
}
Razya Ladelsky committed
645

646 647
/* Mark lattice as containing an unknown value and return true if it previously
   was not marked as such.  */
648

649 650 651 652 653 654
static inline bool
set_lattice_contains_variable (struct ipcp_lattice *lat)
{
  bool ret = !lat->contains_variable;
  lat->contains_variable = true;
  return ret;
Razya Ladelsky committed
655 656
}

657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690
/* Set all aggegate lattices in PLATS to bottom and return true if they were
   not previously set as such.  */

static inline bool
set_agg_lats_to_bottom (struct ipcp_param_lattices *plats)
{
  bool ret = !plats->aggs_bottom;
  plats->aggs_bottom = true;
  return ret;
}

/* Mark all aggegate lattices in PLATS as containing an unknown value and
   return true if they were not previously marked as such.  */

static inline bool
set_agg_lats_contain_variable (struct ipcp_param_lattices *plats)
{
  bool ret = !plats->aggs_contain_variable;
  plats->aggs_contain_variable = true;
  return ret;
}

/* Mark bot aggregate and scalar lattices as containing an unknown variable,
   return true is any of them has not been marked as such so far.  */

static inline bool
set_all_contains_variable (struct ipcp_param_lattices *plats)
{
  bool ret = !plats->itself.contains_variable || !plats->aggs_contain_variable;
  plats->itself.contains_variable = true;
  plats->aggs_contain_variable = true;
  return ret;
}

691
/* Initialize ipcp_lattices.  */
692

Razya Ladelsky committed
693
static void
694
initialize_node_lattices (struct cgraph_node *node)
Razya Ladelsky committed
695
{
696 697 698 699
  struct ipa_node_params *info = IPA_NODE_REF (node);
  struct cgraph_edge *ie;
  bool disable = false, variable = false;
  int i;
Razya Ladelsky committed
700

701
  gcc_checking_assert (cgraph_function_with_gimple_body_p (node));
702
  if (!node->local.local)
703 704 705 706 707 708 709 710 711 712
    {
      /* When cloning is allowed, we can assume that externally visible
	 functions are not called.  We will compensate this by cloning
	 later.  */
      if (ipcp_versionable_function_p (node)
	  && ipcp_cloning_candidate_p (node))
	variable = true;
      else
	disable = true;
    }
Razya Ladelsky committed
713

714 715 716 717
  if (disable || variable)
    {
      for (i = 0; i < ipa_get_param_count (info) ; i++)
	{
718
	  struct ipcp_param_lattices *plats = ipa_get_parm_lattices (info, i);
719
	  if (disable)
720 721 722 723
	    {
	      set_lattice_to_bottom (&plats->itself);
	      set_agg_lats_to_bottom (plats);
	    }
724
	  else
725
	    set_all_contains_variable (plats);
726 727
	}
      if (dump_file && (dump_flags & TDF_DETAILS)
728
	  && !node->alias && !node->thunk.thunk_p)
729 730 731 732
	fprintf (dump_file, "Marking all lattices of %s/%i as %s\n",
		 cgraph_node_name (node), node->uid,
		 disable ? "BOTTOM" : "VARIABLE");
    }
733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748
  if (!disable)
    for (i = 0; i < ipa_get_param_count (info) ; i++)
      {
	struct ipcp_param_lattices *plats = ipa_get_parm_lattices (info, i);
	tree t = TREE_TYPE (ipa_get_param(info, i));

	if (POINTER_TYPE_P (t) && TYPE_RESTRICT (t)
	    && TREE_CODE (TREE_TYPE (t)) == ARRAY_TYPE)
	  {
	    set_lattice_to_bottom (&plats->itself);
	    if (dump_file && (dump_flags & TDF_DETAILS)
		&& !node->alias && !node->thunk.thunk_p)
	      fprintf (dump_file, "Going to ignore param %i of of %s/%i.\n",
		       i, cgraph_node_name (node), node->uid);
	  }
      }
Razya Ladelsky committed
749

750 751
  for (ie = node->indirect_calls; ie; ie = ie->next_callee)
    if (ie->indirect_info->polymorphic)
752
      {
753
	gcc_checking_assert (ie->indirect_info->param_index >= 0);
754 755
	ipa_get_parm_lattices (info,
			       ie->indirect_info->param_index)->virt_call = 1;
756
      }
Razya Ladelsky committed
757 758
}

759 760 761
/* Return the result of a (possibly arithmetic) pass through jump function
   JFUNC on the constant value INPUT.  Return NULL_TREE if that cannot be
   determined or itself is considered an interprocedural invariant.  */
762

763 764
static tree
ipa_get_jf_pass_through_result (struct ipa_jump_func *jfunc, tree input)
765
{
766
  tree restype, res;
767

768
  if (ipa_get_jf_pass_through_operation (jfunc) == NOP_EXPR)
769
    return input;
770 771
  else if (TREE_CODE (input) == TREE_BINFO)
    return NULL_TREE;
772

773 774
  gcc_checking_assert (is_gimple_ip_invariant (input));
  if (TREE_CODE_CLASS (ipa_get_jf_pass_through_operation (jfunc))
775 776 777 778
      == tcc_comparison)
    restype = boolean_type_node;
  else
    restype = TREE_TYPE (input);
779 780
  res = fold_binary (ipa_get_jf_pass_through_operation (jfunc), restype,
		     input, ipa_get_jf_pass_through_operand (jfunc));
781

782 783
  if (res && !is_gimple_ip_invariant (res))
    return NULL_TREE;
784

785
  return res;
786 787
}

788 789
/* Return the result of an ancestor jump function JFUNC on the constant value
   INPUT.  Return NULL_TREE if that cannot be determined.  */
790

791 792
static tree
ipa_get_jf_ancestor_result (struct ipa_jump_func *jfunc, tree input)
793
{
794 795 796 797 798
  if (TREE_CODE (input) == TREE_BINFO)
    return get_binfo_at_offset (input,
				ipa_get_jf_ancestor_offset (jfunc),
				ipa_get_jf_ancestor_type (jfunc));
  else if (TREE_CODE (input) == ADDR_EXPR)
799
    {
800 801
      tree t = TREE_OPERAND (input, 0);
      t = build_ref_for_offset (EXPR_LOCATION (t), t,
802 803
				ipa_get_jf_ancestor_offset (jfunc),
				ipa_get_jf_ancestor_type (jfunc), NULL, false);
804
      return build_fold_addr_expr (t);
805 806
    }
  else
807 808
    return NULL_TREE;
}
809

810 811 812 813 814 815
/* Extract the acual BINFO being described by JFUNC which must be a known type
   jump function.  */

static tree
ipa_value_from_known_type_jfunc (struct ipa_jump_func *jfunc)
{
816
  tree base_binfo = TYPE_BINFO (ipa_get_jf_known_type_base_type (jfunc));
817 818 819
  if (!base_binfo)
    return NULL_TREE;
  return get_binfo_at_offset (base_binfo,
820 821
			      ipa_get_jf_known_type_offset (jfunc),
			      ipa_get_jf_known_type_component_type (jfunc));
822 823
}

824 825 826 827 828
/* Determine whether JFUNC evaluates to a known value (that is either a
   constant or a binfo) and if so, return it.  Otherwise return NULL. INFO
   describes the caller node so that pass-through jump functions can be
   evaluated.  */

829
tree
830 831 832
ipa_value_from_jfunc (struct ipa_node_params *info, struct ipa_jump_func *jfunc)
{
  if (jfunc->type == IPA_JF_CONST)
833
    return ipa_get_jf_constant (jfunc);
834
  else if (jfunc->type == IPA_JF_KNOWN_TYPE)
835
    return ipa_value_from_known_type_jfunc (jfunc);
836 837
  else if (jfunc->type == IPA_JF_PASS_THROUGH
	   || jfunc->type == IPA_JF_ANCESTOR)
838
    {
839 840
      tree input;
      int idx;
841

842
      if (jfunc->type == IPA_JF_PASS_THROUGH)
843
	idx = ipa_get_jf_pass_through_formal_id (jfunc);
844
      else
845
	idx = ipa_get_jf_ancestor_formal_id (jfunc);
846

847
      if (info->ipcp_orig_node)
848
	input = info->known_vals[idx];
849
      else
850
	{
851 852 853
	  struct ipcp_lattice *lat;

	  if (!info->lattices)
854
	    {
855 856
	      gcc_checking_assert (!flag_ipa_cp);
	      return NULL_TREE;
857
	    }
858
	  lat = ipa_get_scalar_lat (info, idx);
859 860 861 862 863 864 865 866 867
	  if (!ipa_lat_is_single_const (lat))
	    return NULL_TREE;
	  input = lat->values->value;
	}

      if (!input)
	return NULL_TREE;

      if (jfunc->type == IPA_JF_PASS_THROUGH)
868
	return ipa_get_jf_pass_through_result (jfunc, input);
869
      else
870
	return ipa_get_jf_ancestor_result (jfunc, input);
871
    }
872 873
  else
    return NULL_TREE;
874 875 876
}


877 878 879
/* If checking is enabled, verify that no lattice is in the TOP state, i.e. not
   bottom, not containing a variable component and without any known value at
   the same time.  */
880

881 882
DEBUG_FUNCTION void
ipcp_verify_propagated_values (void)
Razya Ladelsky committed
883
{
884
  struct cgraph_node *node;
885

886
  FOR_EACH_FUNCTION_WITH_GIMPLE_BODY (node)
Razya Ladelsky committed
887
    {
888
      struct ipa_node_params *info = IPA_NODE_REF (node);
889
      int i, count = ipa_get_param_count (info);
890

891
      for (i = 0; i < count; i++)
Razya Ladelsky committed
892
	{
893
	  struct ipcp_lattice *lat = ipa_get_scalar_lat (info, i);
894

895 896 897
	  if (!lat->bottom
	      && !lat->contains_variable
	      && lat->values_count == 0)
Razya Ladelsky committed
898
	    {
899
	      if (dump_file)
Razya Ladelsky committed
900
		{
901 902 903
		  fprintf (dump_file, "\nIPA lattices after constant "
			   "propagation:\n");
		  print_all_lattices (dump_file, true, false);
Razya Ladelsky committed
904
		}
905

906
	      gcc_unreachable ();
Razya Ladelsky committed
907 908 909 910 911
	    }
	}
    }
}

912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936
/* Return true iff X and Y should be considered equal values by IPA-CP.  */

static bool
values_equal_for_ipcp_p (tree x, tree y)
{
  gcc_checking_assert (x != NULL_TREE && y != NULL_TREE);

  if (x == y)
    return true;

  if (TREE_CODE (x) == TREE_BINFO || TREE_CODE (y) == TREE_BINFO)
    return false;

  if (TREE_CODE (x) ==  ADDR_EXPR
      && TREE_CODE (y) ==  ADDR_EXPR
      && TREE_CODE (TREE_OPERAND (x, 0)) == CONST_DECL
      && TREE_CODE (TREE_OPERAND (y, 0)) == CONST_DECL)
    return operand_equal_p (DECL_INITIAL (TREE_OPERAND (x, 0)),
			    DECL_INITIAL (TREE_OPERAND (y, 0)), 0);
  else
    return operand_equal_p (x, y, 0);
}

/* Add a new value source to VAL, marking that a value comes from edge CS and
   (if the underlying jump function is a pass-through or an ancestor one) from
937 938 939
   a caller value SRC_VAL of a caller parameter described by SRC_INDEX.  OFFSET
   is negative if the source was the scalar value of the parameter itself or
   the offset within an aggregate.  */
940

Razya Ladelsky committed
941
static void
942
add_value_source (struct ipcp_value *val, struct cgraph_edge *cs,
943
		  struct ipcp_value *src_val, int src_idx, HOST_WIDE_INT offset)
Razya Ladelsky committed
944
{
945
  struct ipcp_value_source *src;
946

947
  src = (struct ipcp_value_source *) pool_alloc (ipcp_sources_pool);
948
  src->offset = offset;
949 950 951
  src->cs = cs;
  src->val = src_val;
  src->index = src_idx;
952

953 954 955 956 957
  src->next = val->sources;
  val->sources = src;
}

/* Try to add NEWVAL to LAT, potentially creating a new struct ipcp_value for
958 959
   it.  CS, SRC_VAL SRC_INDEX and OFFSET are meant for add_value_source and
   have the same meaning.  */
960 961 962 963

static bool
add_value_to_lattice (struct ipcp_lattice *lat, tree newval,
		      struct cgraph_edge *cs, struct ipcp_value *src_val,
964
		      int src_idx, HOST_WIDE_INT offset)
965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983
{
  struct ipcp_value *val;

  if (lat->bottom)
    return false;

  for (val = lat->values; val; val = val->next)
    if (values_equal_for_ipcp_p (val->value, newval))
      {
	if (edge_within_scc (cs))
	  {
	    struct ipcp_value_source *s;
	    for (s = val->sources; s ; s = s->next)
	      if (s->cs == cs)
		break;
	    if (s)
	      return false;
	  }

984
	add_value_source (val, cs, src_val, src_idx, offset);
985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009
	return false;
      }

  if (lat->values_count == PARAM_VALUE (PARAM_IPA_CP_VALUE_LIST_SIZE))
    {
      /* We can only free sources, not the values themselves, because sources
	 of other values in this this SCC might point to them.   */
      for (val = lat->values; val; val = val->next)
	{
	  while (val->sources)
	    {
	      struct ipcp_value_source *src = val->sources;
	      val->sources = src->next;
	      pool_free (ipcp_sources_pool, src);
	    }
	}

      lat->values = NULL;
      return set_lattice_to_bottom (lat);
    }

  lat->values_count++;
  val = (struct ipcp_value *) pool_alloc (ipcp_values_pool);
  memset (val, 0, sizeof (*val));

1010
  add_value_source (val, cs, src_val, src_idx, offset);
1011 1012 1013 1014 1015
  val->value = newval;
  val->next = lat->values;
  lat->values = val;
  return true;
}
1016

1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028
/* Like above but passes a special value of offset to distinguish that the
   origin is the scalar value of the parameter rather than a part of an
   aggregate.  */

static inline bool
add_scalar_value_to_lattice (struct ipcp_lattice *lat, tree newval,
			     struct cgraph_edge *cs,
			     struct ipcp_value *src_val, int src_idx)
{
  return add_value_to_lattice (lat, newval, cs, src_val, src_idx, -1);
}

1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042
/* Propagate values through a pass-through jump function JFUNC associated with
   edge CS, taking values from SRC_LAT and putting them into DEST_LAT.  SRC_IDX
   is the index of the source parameter.  */

static bool
propagate_vals_accross_pass_through (struct cgraph_edge *cs,
				     struct ipa_jump_func *jfunc,
				     struct ipcp_lattice *src_lat,
				     struct ipcp_lattice *dest_lat,
				     int src_idx)
{
  struct ipcp_value *src_val;
  bool ret = false;

1043
  if (ipa_get_jf_pass_through_operation (jfunc) == NOP_EXPR)
1044
    for (src_val = src_lat->values; src_val; src_val = src_val->next)
1045 1046
      ret |= add_scalar_value_to_lattice (dest_lat, src_val->value, cs,
					  src_val, src_idx);
1047
  /* Do not create new values when propagating within an SCC because if there
1048 1049
     are arithmetic functions with circular dependencies, there is infinite
     number of them and we would just make lattices bottom.  */
1050 1051 1052 1053
  else if (edge_within_scc (cs))
    ret = set_lattice_contains_variable (dest_lat);
  else
    for (src_val = src_lat->values; src_val; src_val = src_val->next)
1054
      {
1055 1056 1057 1058 1059 1060 1061 1062 1063 1064
	tree cstval = src_val->value;

	if (TREE_CODE (cstval) == TREE_BINFO)
	  {
	    ret |= set_lattice_contains_variable (dest_lat);
	    continue;
	  }
	cstval = ipa_get_jf_pass_through_result (jfunc, cstval);

	if (cstval)
1065 1066
	  ret |= add_scalar_value_to_lattice (dest_lat, cstval, cs, src_val,
					      src_idx);
1067 1068
	else
	  ret |= set_lattice_contains_variable (dest_lat);
1069
      }
1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092

  return ret;
}

/* Propagate values through an ancestor jump function JFUNC associated with
   edge CS, taking values from SRC_LAT and putting them into DEST_LAT.  SRC_IDX
   is the index of the source parameter.  */

static bool
propagate_vals_accross_ancestor (struct cgraph_edge *cs,
				 struct ipa_jump_func *jfunc,
				 struct ipcp_lattice *src_lat,
				 struct ipcp_lattice *dest_lat,
				 int src_idx)
{
  struct ipcp_value *src_val;
  bool ret = false;

  if (edge_within_scc (cs))
    return set_lattice_contains_variable (dest_lat);

  for (src_val = src_lat->values; src_val; src_val = src_val->next)
    {
1093
      tree t = ipa_get_jf_ancestor_result (jfunc, src_val->value);
1094 1095

      if (t)
1096
	ret |= add_scalar_value_to_lattice (dest_lat, t, cs, src_val, src_idx);
1097 1098 1099 1100 1101 1102 1103
      else
	ret |= set_lattice_contains_variable (dest_lat);
    }

  return ret;
}

1104 1105
/* Propagate scalar values across jump function JFUNC that is associated with
   edge CS and put the values into DEST_LAT.  */
1106 1107

static bool
1108 1109 1110
propagate_scalar_accross_jump_function (struct cgraph_edge *cs,
					struct ipa_jump_func *jfunc,
					struct ipcp_lattice *dest_lat)
1111 1112 1113 1114 1115 1116 1117 1118 1119 1120
{
  if (dest_lat->bottom)
    return false;

  if (jfunc->type == IPA_JF_CONST
      || jfunc->type == IPA_JF_KNOWN_TYPE)
    {
      tree val;

      if (jfunc->type == IPA_JF_KNOWN_TYPE)
1121 1122 1123 1124 1125
	{
	  val = ipa_value_from_known_type_jfunc (jfunc);
	  if (!val)
	    return set_lattice_contains_variable (dest_lat);
	}
1126
      else
1127
	val = ipa_get_jf_constant (jfunc);
1128
      return add_scalar_value_to_lattice (dest_lat, val, cs, NULL, 0);
1129 1130 1131 1132 1133 1134 1135 1136 1137 1138
    }
  else if (jfunc->type == IPA_JF_PASS_THROUGH
	   || jfunc->type == IPA_JF_ANCESTOR)
    {
      struct ipa_node_params *caller_info = IPA_NODE_REF (cs->caller);
      struct ipcp_lattice *src_lat;
      int src_idx;
      bool ret;

      if (jfunc->type == IPA_JF_PASS_THROUGH)
1139
	src_idx = ipa_get_jf_pass_through_formal_id (jfunc);
1140
      else
1141
	src_idx = ipa_get_jf_ancestor_formal_id (jfunc);
1142

1143
      src_lat = ipa_get_scalar_lat (caller_info, src_idx);
1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170
      if (src_lat->bottom)
	return set_lattice_contains_variable (dest_lat);

      /* If we would need to clone the caller and cannot, do not propagate.  */
      if (!ipcp_versionable_function_p (cs->caller)
	  && (src_lat->contains_variable
	      || (src_lat->values_count > 1)))
	return set_lattice_contains_variable (dest_lat);

      if (jfunc->type == IPA_JF_PASS_THROUGH)
	ret = propagate_vals_accross_pass_through (cs, jfunc, src_lat,
						   dest_lat, src_idx);
      else
	ret = propagate_vals_accross_ancestor (cs, jfunc, src_lat, dest_lat,
					       src_idx);

      if (src_lat->contains_variable)
	ret |= set_lattice_contains_variable (dest_lat);

      return ret;
    }

  /* TODO: We currently do not handle member method pointers in IPA-CP (we only
     use it for indirect inlining), we should propagate them too.  */
  return set_lattice_contains_variable (dest_lat);
}

1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293
/* If DEST_PLATS already has aggregate items, check that aggs_by_ref matches
   NEW_AGGS_BY_REF and if not, mark all aggs as bottoms and return true (in all
   other cases, return false).  If there are no aggregate items, set
   aggs_by_ref to NEW_AGGS_BY_REF.  */

static bool
set_check_aggs_by_ref (struct ipcp_param_lattices *dest_plats,
		       bool new_aggs_by_ref)
{
  if (dest_plats->aggs)
    {
      if (dest_plats->aggs_by_ref != new_aggs_by_ref)
	{
	  set_agg_lats_to_bottom (dest_plats);
	  return true;
	}
    }
  else
    dest_plats->aggs_by_ref = new_aggs_by_ref;
  return false;
}

/* Walk aggregate lattices in DEST_PLATS from ***AGLAT on, until ***aglat is an
   already existing lattice for the given OFFSET and SIZE, marking all skipped
   lattices as containing variable and checking for overlaps.  If there is no
   already existing lattice for the OFFSET and VAL_SIZE, create one, initialize
   it with offset, size and contains_variable to PRE_EXISTING, and return true,
   unless there are too many already.  If there are two many, return false.  If
   there are overlaps turn whole DEST_PLATS to bottom and return false.  If any
   skipped lattices were newly marked as containing variable, set *CHANGE to
   true.  */

static bool
merge_agg_lats_step (struct ipcp_param_lattices *dest_plats,
		     HOST_WIDE_INT offset, HOST_WIDE_INT val_size,
		     struct ipcp_agg_lattice ***aglat,
		     bool pre_existing, bool *change)
{
  gcc_checking_assert (offset >= 0);

  while (**aglat && (**aglat)->offset < offset)
    {
      if ((**aglat)->offset + (**aglat)->size > offset)
	{
	  set_agg_lats_to_bottom (dest_plats);
	  return false;
	}
      *change |= set_lattice_contains_variable (**aglat);
      *aglat = &(**aglat)->next;
    }

  if (**aglat && (**aglat)->offset == offset)
    {
      if ((**aglat)->size != val_size
          || ((**aglat)->next
              && (**aglat)->next->offset < offset + val_size))
	{
	  set_agg_lats_to_bottom (dest_plats);
	  return false;
	}
      gcc_checking_assert (!(**aglat)->next
			   || (**aglat)->next->offset >= offset + val_size);
      return true;
    }
  else
    {
      struct ipcp_agg_lattice *new_al;

      if (**aglat && (**aglat)->offset < offset + val_size)
	{
	  set_agg_lats_to_bottom (dest_plats);
	  return false;
	}
      if (dest_plats->aggs_count == PARAM_VALUE (PARAM_IPA_MAX_AGG_ITEMS))
	return false;
      dest_plats->aggs_count++;
      new_al = (struct ipcp_agg_lattice *) pool_alloc (ipcp_agg_lattice_pool);
      memset (new_al, 0, sizeof (*new_al));

      new_al->offset = offset;
      new_al->size = val_size;
      new_al->contains_variable = pre_existing;

      new_al->next = **aglat;
      **aglat = new_al;
      return true;
    }
}

/* Set all AGLAT and all other aggregate lattices reachable by next pointers as
   containing an unknown value.  */

static bool
set_chain_of_aglats_contains_variable (struct ipcp_agg_lattice *aglat)
{
  bool ret = false;
  while (aglat)
    {
      ret |= set_lattice_contains_variable (aglat);
      aglat = aglat->next;
    }
  return ret;
}

/* Merge existing aggregate lattices in SRC_PLATS to DEST_PLATS, subtracting
   DELTA_OFFSET.  CS is the call graph edge and SRC_IDX the index of the source
   parameter used for lattice value sources.  Return true if DEST_PLATS changed
   in any way.  */

static bool
merge_aggregate_lattices (struct cgraph_edge *cs,
			  struct ipcp_param_lattices *dest_plats,
			  struct ipcp_param_lattices *src_plats,
			  int src_idx, HOST_WIDE_INT offset_delta)
{
  bool pre_existing = dest_plats->aggs != NULL;
  struct ipcp_agg_lattice **dst_aglat;
  bool ret = false;

  if (set_check_aggs_by_ref (dest_plats, src_plats->aggs_by_ref))
    return true;
  if (src_plats->aggs_bottom)
    return set_agg_lats_contain_variable (dest_plats);
1294 1295
  if (src_plats->aggs_contain_variable)
    ret |= set_agg_lats_contain_variable (dest_plats);
1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331
  dst_aglat = &dest_plats->aggs;

  for (struct ipcp_agg_lattice *src_aglat = src_plats->aggs;
       src_aglat;
       src_aglat = src_aglat->next)
    {
      HOST_WIDE_INT new_offset = src_aglat->offset - offset_delta;

      if (new_offset < 0)
	continue;
      if (merge_agg_lats_step (dest_plats, new_offset, src_aglat->size,
			       &dst_aglat, pre_existing, &ret))
	{
	  struct ipcp_agg_lattice *new_al = *dst_aglat;

	  dst_aglat = &(*dst_aglat)->next;
	  if (src_aglat->bottom)
	    {
	      ret |= set_lattice_contains_variable (new_al);
	      continue;
	    }
	  if (src_aglat->contains_variable)
	    ret |= set_lattice_contains_variable (new_al);
	  for (struct ipcp_value *val = src_aglat->values;
	       val;
	       val = val->next)
	    ret |= add_value_to_lattice (new_al, val->value, cs, val, src_idx,
					 src_aglat->offset);
	}
      else if (dest_plats->aggs_bottom)
	return true;
    }
  ret |= set_chain_of_aglats_contains_variable (*dst_aglat);
  return ret;
}

1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344
/* Determine whether there is anything to propagate FROM SRC_PLATS through a
   pass-through JFUNC and if so, whether it has conform and conforms to the
   rules about propagating values passed by reference.  */

static bool
agg_pass_through_permissible_p (struct ipcp_param_lattices *src_plats,
				struct ipa_jump_func *jfunc)
{
  return src_plats->aggs
    && (!src_plats->aggs_by_ref
	|| ipa_get_jf_pass_through_agg_preserved (jfunc));
}

1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365
/* Propagate scalar values across jump function JFUNC that is associated with
   edge CS and put the values into DEST_LAT.  */

static bool
propagate_aggs_accross_jump_function (struct cgraph_edge *cs,
				      struct ipa_jump_func *jfunc,
				      struct ipcp_param_lattices *dest_plats)
{
  bool ret = false;

  if (dest_plats->aggs_bottom)
    return false;

  if (jfunc->type == IPA_JF_PASS_THROUGH
      && ipa_get_jf_pass_through_operation (jfunc) == NOP_EXPR)
    {
      struct ipa_node_params *caller_info = IPA_NODE_REF (cs->caller);
      int src_idx = ipa_get_jf_pass_through_formal_id (jfunc);
      struct ipcp_param_lattices *src_plats;

      src_plats = ipa_get_parm_lattices (caller_info, src_idx);
1366
      if (agg_pass_through_permissible_p (src_plats, jfunc))
1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407
	{
	  /* Currently we do not produce clobber aggregate jump
	     functions, replace with merging when we do.  */
	  gcc_assert (!jfunc->agg.items);
	  ret |= merge_aggregate_lattices (cs, dest_plats, src_plats,
					   src_idx, 0);
	}
      else
	ret |= set_agg_lats_contain_variable (dest_plats);
    }
  else if (jfunc->type == IPA_JF_ANCESTOR
	   && ipa_get_jf_ancestor_agg_preserved (jfunc))
    {
      struct ipa_node_params *caller_info = IPA_NODE_REF (cs->caller);
      int src_idx = ipa_get_jf_ancestor_formal_id (jfunc);
      struct ipcp_param_lattices *src_plats;

      src_plats = ipa_get_parm_lattices (caller_info, src_idx);
      if (src_plats->aggs && src_plats->aggs_by_ref)
	{
	  /* Currently we do not produce clobber aggregate jump
	     functions, replace with merging when we do.  */
	  gcc_assert (!jfunc->agg.items);
	  ret |= merge_aggregate_lattices (cs, dest_plats, src_plats, src_idx,
					   ipa_get_jf_ancestor_offset (jfunc));
	}
      else if (!src_plats->aggs_by_ref)
	ret |= set_agg_lats_to_bottom (dest_plats);
      else
	ret |= set_agg_lats_contain_variable (dest_plats);
    }
  else if (jfunc->agg.items)
    {
      bool pre_existing = dest_plats->aggs != NULL;
      struct ipcp_agg_lattice **aglat = &dest_plats->aggs;
      struct ipa_agg_jf_item *item;
      int i;

      if (set_check_aggs_by_ref (dest_plats, jfunc->agg.by_ref))
	return true;

1408
      FOR_EACH_VEC_ELT (*jfunc->agg.items, i, item)
1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434
	{
	  HOST_WIDE_INT val_size;

	  if (item->offset < 0)
	    continue;
	  gcc_checking_assert (is_gimple_ip_invariant (item->value));
	  val_size = tree_low_cst (TYPE_SIZE (TREE_TYPE (item->value)), 1);

	  if (merge_agg_lats_step (dest_plats, item->offset, val_size,
				   &aglat, pre_existing, &ret))
	    {
	      ret |= add_value_to_lattice (*aglat, item->value, cs, NULL, 0, 0);
	      aglat = &(*aglat)->next;
	    }
	  else if (dest_plats->aggs_bottom)
	    return true;
	}

      ret |= set_chain_of_aglats_contains_variable (*aglat);
    }
  else
    ret |= set_agg_lats_contain_variable (dest_plats);

  return ret;
}

1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445
/* Propagate constants from the caller to the callee of CS.  INFO describes the
   caller.  */

static bool
propagate_constants_accross_call (struct cgraph_edge *cs)
{
  struct ipa_node_params *callee_info;
  enum availability availability;
  struct cgraph_node *callee, *alias_or_thunk;
  struct ipa_edge_args *args;
  bool ret = false;
1446
  int i, args_count, parms_count;
1447 1448 1449 1450 1451 1452 1453 1454

  callee = cgraph_function_node (cs->callee, &availability);
  if (!callee->analyzed)
    return false;
  gcc_checking_assert (cgraph_function_with_gimple_body_p (callee));
  callee_info = IPA_NODE_REF (callee);

  args = IPA_EDGE_REF (cs);
1455 1456
  args_count = ipa_get_cs_argument_count (args);
  parms_count = ipa_get_param_count (callee_info);
1457 1458 1459 1460 1461 1462 1463 1464 1465

  /* If this call goes through a thunk we must not propagate to the first (0th)
     parameter.  However, we might need to uncover a thunk from below a series
     of aliases first.  */
  alias_or_thunk = cs->callee;
  while (alias_or_thunk->alias)
    alias_or_thunk = cgraph_alias_aliased_node (alias_or_thunk);
  if (alias_or_thunk->thunk.thunk_p)
    {
1466 1467
      ret |= set_all_contains_variable (ipa_get_parm_lattices (callee_info,
							       0));
1468 1469 1470 1471 1472
      i = 1;
    }
  else
    i = 0;

1473
  for (; (i < args_count) && (i < parms_count); i++)
1474 1475
    {
      struct ipa_jump_func *jump_func = ipa_get_ith_jump_func (args, i);
1476
      struct ipcp_param_lattices *dest_plats;
1477

1478
      dest_plats = ipa_get_parm_lattices (callee_info, i);
1479
      if (availability == AVAIL_OVERWRITABLE)
1480
	ret |= set_all_contains_variable (dest_plats);
1481
      else
1482 1483 1484 1485 1486 1487
	{
	  ret |= propagate_scalar_accross_jump_function (cs, jump_func,
							 &dest_plats->itself);
	  ret |= propagate_aggs_accross_jump_function (cs, jump_func,
						       dest_plats);
	}
1488
    }
1489
  for (; i < parms_count; i++)
1490
    ret |= set_all_contains_variable (ipa_get_parm_lattices (callee_info, i));
1491

1492 1493 1494 1495 1496
  return ret;
}

/* If an indirect edge IE can be turned into a direct one based on KNOWN_VALS
   (which can contain both constants and binfos) or KNOWN_BINFOS (which can be
1497
   NULL) return the destination.  */
1498

1499 1500
tree
ipa_get_indirect_edge_target (struct cgraph_edge *ie,
1501 1502 1503
			      vec<tree> known_vals,
			      vec<tree> known_binfos,
			      vec<ipa_agg_jump_function_p> known_aggs)
1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514
{
  int param_index = ie->indirect_info->param_index;
  HOST_WIDE_INT token, anc_offset;
  tree otr_type;
  tree t;

  if (param_index == -1)
    return NULL_TREE;

  if (!ie->indirect_info->polymorphic)
    {
1515 1516 1517 1518
      tree t;

      if (ie->indirect_info->agg_contents)
	{
1519
	  if (known_aggs.length ()
1520 1521 1522
	      > (unsigned int) param_index)
	    {
	      struct ipa_agg_jump_function *agg;
1523
	      agg = known_aggs[param_index];
1524 1525 1526 1527 1528 1529 1530
	      t = ipa_find_agg_cst_for_param (agg, ie->indirect_info->offset,
					      ie->indirect_info->by_ref);
	    }
	  else
	    t = NULL;
	}
      else
1531 1532
	t = (known_vals.length () > (unsigned int) param_index
	     ? known_vals[param_index] : NULL);
1533

1534 1535 1536
      if (t &&
	  TREE_CODE (t) == ADDR_EXPR
	  && TREE_CODE (TREE_OPERAND (t, 0)) == FUNCTION_DECL)
1537
	return TREE_OPERAND (t, 0);
1538 1539 1540 1541
      else
	return NULL_TREE;
    }

1542
  gcc_assert (!ie->indirect_info->agg_contents);
1543
  token = ie->indirect_info->otr_token;
1544
  anc_offset = ie->indirect_info->offset;
1545 1546
  otr_type = ie->indirect_info->otr_type;

1547 1548 1549
  t = known_vals[param_index];
  if (!t && known_binfos.length () > (unsigned int) param_index)
    t = known_binfos[param_index];
1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561
  if (!t)
    return NULL_TREE;

  if (TREE_CODE (t) != TREE_BINFO)
    {
      tree binfo;
      binfo = gimple_extract_devirt_binfo_from_cst (t);
      if (!binfo)
	return NULL_TREE;
      binfo = get_binfo_at_offset (binfo, anc_offset, otr_type);
      if (!binfo)
	return NULL_TREE;
1562
      return gimple_get_virt_method_for_binfo (token, binfo);
1563 1564 1565 1566 1567 1568 1569 1570
    }
  else
    {
      tree binfo;

      binfo = get_binfo_at_offset (t, anc_offset, otr_type);
      if (!binfo)
	return NULL_TREE;
1571
      return gimple_get_virt_method_for_binfo (token, binfo);
1572 1573 1574 1575 1576 1577 1578 1579
    }
}

/* Calculate devirtualization time bonus for NODE, assuming we know KNOWN_CSTS
   and KNOWN_BINFOS.  */

static int
devirtualization_time_bonus (struct cgraph_node *node,
1580 1581
			     vec<tree> known_csts,
			     vec<tree> known_binfos)
1582 1583 1584 1585 1586 1587 1588 1589
{
  struct cgraph_edge *ie;
  int res = 0;

  for (ie = node->indirect_calls; ie; ie = ie->next_callee)
    {
      struct cgraph_node *callee;
      struct inline_summary *isummary;
1590
      tree target;
1591

1592
      target = ipa_get_indirect_edge_target (ie, known_csts, known_binfos,
1593
					vNULL);
1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612
      if (!target)
	continue;

      /* Only bare minimum benefit for clearly un-inlineable targets.  */
      res += 1;
      callee = cgraph_get_node (target);
      if (!callee || !callee->analyzed)
	continue;
      isummary = inline_summary (callee);
      if (!isummary->inlinable)
	continue;

      /* FIXME: The values below need re-considering and perhaps also
	 integrating into the cost metrics, at lest in some very basic way.  */
      if (isummary->size <= MAX_INLINE_INSNS_AUTO / 4)
	res += 31;
      else if (isummary->size <= MAX_INLINE_INSNS_AUTO / 2)
	res += 15;
      else if (isummary->size <= MAX_INLINE_INSNS_AUTO
1613
	       || DECL_DECLARED_INLINE_P (callee->symbol.decl))
1614 1615 1616 1617 1618 1619
	res += 7;
    }

  return res;
}

1620 1621 1622 1623 1624 1625 1626 1627 1628 1629
/* Return time bonus incurred because of HINTS.  */

static int
hint_time_bonus (inline_hints hints)
{
  if (hints & (INLINE_HINT_loop_iterations | INLINE_HINT_loop_stride))
    return PARAM_VALUE (PARAM_IPA_CP_LOOP_HINT_BONUS);
  return 0;
}

1630 1631 1632 1633 1634 1635 1636 1637 1638 1639
/* Return true if cloning NODE is a good idea, given the estimated TIME_BENEFIT
   and SIZE_COST and with the sum of frequencies of incoming edges to the
   potential new clone in FREQUENCIES.  */

static bool
good_cloning_opportunity_p (struct cgraph_node *node, int time_benefit,
			    int freq_sum, gcov_type count_sum, int size_cost)
{
  if (time_benefit == 0
      || !flag_ipa_cp_clone
1640
      || !optimize_function_for_speed_p (DECL_STRUCT_FUNCTION (node->symbol.decl)))
1641 1642
    return false;

1643
  gcc_assert (size_cost > 0);
1644 1645 1646

  if (max_count)
    {
1647 1648 1649
      int factor = (count_sum * 1000) / max_count;
      HOST_WIDEST_INT evaluation = (((HOST_WIDEST_INT) time_benefit * factor)
				    / size_cost);
1650 1651 1652 1653

      if (dump_file && (dump_flags & TDF_DETAILS))
	fprintf (dump_file, "     good_cloning_opportunity_p (time: %i, "
		 "size: %i, count_sum: " HOST_WIDE_INT_PRINT_DEC
1654 1655
		 ") -> evaluation: " HOST_WIDEST_INT_PRINT_DEC
		 ", threshold: %i\n",
1656
		 time_benefit, size_cost, (HOST_WIDE_INT) count_sum,
1657
		 evaluation, PARAM_VALUE (PARAM_IPA_CP_EVAL_THRESHOLD));
1658 1659 1660 1661 1662

      return evaluation >= PARAM_VALUE (PARAM_IPA_CP_EVAL_THRESHOLD);
    }
  else
    {
1663 1664
      HOST_WIDEST_INT evaluation = (((HOST_WIDEST_INT) time_benefit * freq_sum)
				    / size_cost);
1665 1666 1667

      if (dump_file && (dump_flags & TDF_DETAILS))
	fprintf (dump_file, "     good_cloning_opportunity_p (time: %i, "
1668 1669
		 "size: %i, freq_sum: %i) -> evaluation: "
		 HOST_WIDEST_INT_PRINT_DEC ", threshold: %i\n",
1670
		 time_benefit, size_cost, freq_sum, evaluation,
1671
		 PARAM_VALUE (PARAM_IPA_CP_EVAL_THRESHOLD));
1672 1673 1674 1675 1676

      return evaluation >= PARAM_VALUE (PARAM_IPA_CP_EVAL_THRESHOLD);
    }
}

1677 1678 1679
/* Return all context independent values from aggregate lattices in PLATS in a
   vector.  Return NULL if there are none.  */

1680
static vec<ipa_agg_jf_item_t, va_gc> *
1681 1682
context_independent_aggregate_values (struct ipcp_param_lattices *plats)
{
1683
  vec<ipa_agg_jf_item_t, va_gc> *res = NULL;
1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697

  if (plats->aggs_bottom
      || plats->aggs_contain_variable
      || plats->aggs_count == 0)
    return NULL;

  for (struct ipcp_agg_lattice *aglat = plats->aggs;
       aglat;
       aglat = aglat->next)
    if (ipa_lat_is_single_const (aglat))
      {
	struct ipa_agg_jf_item item;
	item.offset = aglat->offset;
	item.value = aglat->values->value;
1698
	vec_safe_push (res, item);
1699 1700 1701
      }
  return res;
}
1702

1703 1704 1705 1706
/* Allocate KNOWN_CSTS, KNOWN_BINFOS and, if non-NULL, KNOWN_AGGS and populate
   them with values of parameters that are known independent of the context.
   INFO describes the function.  If REMOVABLE_PARAMS_COST is non-NULL, the
   movement cost of all removable parameters will be stored in it.  */
1707 1708 1709

static bool
gather_context_independent_values (struct ipa_node_params *info,
1710 1711 1712
			       vec<tree> *known_csts,
			       vec<tree> *known_binfos,
			       vec<ipa_agg_jump_function_t> *known_aggs,
1713
			       int *removable_params_cost)
1714 1715 1716 1717
{
  int i, count = ipa_get_param_count (info);
  bool ret = false;

1718 1719 1720 1721
  known_csts->create (0);
  known_binfos->create (0);
  known_csts->safe_grow_cleared (count);
  known_binfos->safe_grow_cleared (count);
1722 1723
  if (known_aggs)
    {
1724 1725
      known_aggs->create (0);
      known_aggs->safe_grow_cleared (count);
1726
    }
1727 1728 1729 1730 1731 1732

  if (removable_params_cost)
    *removable_params_cost = 0;

  for (i = 0; i < count ; i++)
    {
1733 1734
      struct ipcp_param_lattices *plats = ipa_get_parm_lattices (info, i);
      struct ipcp_lattice *lat = &plats->itself;
1735 1736 1737 1738 1739 1740

      if (ipa_lat_is_single_const (lat))
	{
	  struct ipcp_value *val = lat->values;
	  if (TREE_CODE (val->value) != TREE_BINFO)
	    {
1741
	      (*known_csts)[i] = val->value;
1742 1743 1744 1745 1746
	      if (removable_params_cost)
		*removable_params_cost
		  += estimate_move_cost (TREE_TYPE (val->value));
	      ret = true;
	    }
1747
	  else if (plats->virt_call)
1748
	    {
1749
	      (*known_binfos)[i] = val->value;
1750 1751 1752 1753 1754 1755 1756 1757 1758 1759
	      ret = true;
	    }
	  else if (removable_params_cost
		   && !ipa_is_param_used (info, i))
	    *removable_params_cost
	      += estimate_move_cost (TREE_TYPE (ipa_get_param (info, i)));
	}
      else if (removable_params_cost
	       && !ipa_is_param_used (info, i))
	*removable_params_cost
1760 1761 1762 1763
	  += estimate_move_cost (TREE_TYPE (ipa_get_param (info, i)));

      if (known_aggs)
	{
1764
	  vec<ipa_agg_jf_item_t, va_gc> *agg_items;
1765 1766 1767
	  struct ipa_agg_jump_function *ajf;

	  agg_items = context_independent_aggregate_values (plats);
1768
	  ajf = &(*known_aggs)[i];
1769 1770 1771 1772
	  ajf->items = agg_items;
	  ajf->by_ref = plats->aggs_by_ref;
	  ret |= agg_items != NULL;
	}
1773 1774 1775 1776 1777
    }

  return ret;
}

1778 1779 1780 1781 1782 1783 1784
/* The current interface in ipa-inline-analysis requires a pointer vector.
   Create it.

   FIXME: That interface should be re-worked, this is slightly silly.  Still,
   I'd like to discuss how to change it first and this demonstrates the
   issue.  */

1785 1786
static vec<ipa_agg_jump_function_p>
agg_jmp_p_vec_for_t_vec (vec<ipa_agg_jump_function_t> known_aggs)
1787
{
1788
  vec<ipa_agg_jump_function_p> ret;
1789 1790 1791
  struct ipa_agg_jump_function *ajf;
  int i;

1792 1793 1794
  ret.create (known_aggs.length ());
  FOR_EACH_VEC_ELT (known_aggs, i, ajf)
    ret.quick_push (ajf);
1795 1796 1797
  return ret;
}

1798 1799 1800 1801 1802 1803 1804 1805
/* Iterate over known values of parameters of NODE and estimate the local
   effects in terms of time and size they have.  */

static void
estimate_local_effects (struct cgraph_node *node)
{
  struct ipa_node_params *info = IPA_NODE_REF (node);
  int i, count = ipa_get_param_count (info);
1806 1807 1808
  vec<tree> known_csts, known_binfos;
  vec<ipa_agg_jump_function_t> known_aggs;
  vec<ipa_agg_jump_function_p> known_aggs_ptrs;
1809 1810 1811 1812 1813 1814 1815
  bool always_const;
  int base_time = inline_summary (node)->time;
  int removable_params_cost;

  if (!count || !ipcp_versionable_function_p (node))
    return;

1816
  if (dump_file && (dump_flags & TDF_DETAILS))
1817 1818 1819 1820
    fprintf (dump_file, "\nEstimating effects for %s/%i, base_time: %i.\n",
	     cgraph_node_name (node), node->uid, base_time);

  always_const = gather_context_independent_values (info, &known_csts,
1821
						    &known_binfos, &known_aggs,
1822
						    &removable_params_cost);
1823
  known_aggs_ptrs = agg_jmp_p_vec_for_t_vec (known_aggs);
1824
  if (always_const)
1825
    {
1826
      struct caller_statistics stats;
1827
      inline_hints hints;
1828 1829 1830 1831
      int time, size;

      init_caller_stats (&stats);
      cgraph_for_node_and_aliases (node, gather_caller_stats, &stats, false);
1832
      estimate_ipcp_clone_size_and_time (node, known_csts, known_binfos,
1833
					 known_aggs_ptrs, &size, &time, &hints);
1834
      time -= devirtualization_time_bonus (node, known_csts, known_binfos);
1835
      time -= hint_time_bonus (hints);
1836 1837 1838 1839 1840 1841 1842 1843 1844 1845
      time -= removable_params_cost;
      size -= stats.n_calls * removable_params_cost;

      if (dump_file)
	fprintf (dump_file, " - context independent values, size: %i, "
		 "time_benefit: %i\n", size, base_time - time);

      if (size <= 0
	  || cgraph_will_be_removed_from_program_if_no_direct_calls (node))
	{
1846
	  info->do_clone_for_all_contexts = true;
1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858
	  base_time = time;

	  if (dump_file)
	    fprintf (dump_file, "     Decided to specialize for all "
		     "known contexts, code not going to grow.\n");
	}
      else if (good_cloning_opportunity_p (node, base_time - time,
					   stats.freq_sum, stats.count_sum,
					   size))
	{
	  if (size + overall_size <= max_new_size)
	    {
1859
	      info->do_clone_for_all_contexts = true;
1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871
	      base_time = time;
	      overall_size += size;

	      if (dump_file)
		fprintf (dump_file, "     Decided to specialize for all "
			 "known contexts, growth deemed beneficial.\n");
	    }
	  else if (dump_file && (dump_flags & TDF_DETAILS))
	    fprintf (dump_file, "   Not cloning for all contexts because "
		     "max_new_size would be reached with %li.\n",
		     size + overall_size);
	}
1872 1873
    }

1874
  for (i = 0; i < count ; i++)
1875
    {
1876 1877
      struct ipcp_param_lattices *plats = ipa_get_parm_lattices (info, i);
      struct ipcp_lattice *lat = &plats->itself;
1878 1879 1880 1881 1882
      struct ipcp_value *val;
      int emc;

      if (lat->bottom
	  || !lat->values
1883 1884
	  || known_csts[i]
	  || known_binfos[i])
1885 1886 1887 1888 1889
	continue;

      for (val = lat->values; val; val = val->next)
	{
	  int time, size, time_benefit;
1890
	  inline_hints hints;
1891 1892 1893

	  if (TREE_CODE (val->value) != TREE_BINFO)
	    {
1894 1895
	      known_csts[i] = val->value;
	      known_binfos[i] = NULL_TREE;
1896 1897
	      emc = estimate_move_cost (TREE_TYPE (val->value));
	    }
1898
	  else if (plats->virt_call)
1899
	    {
1900 1901
	      known_csts[i] = NULL_TREE;
	      known_binfos[i] = val->value;
1902 1903 1904 1905 1906
	      emc = 0;
	    }
	  else
	    continue;

1907
	  estimate_ipcp_clone_size_and_time (node, known_csts, known_binfos,
1908 1909
					     known_aggs_ptrs, &size, &time,
					     &hints);
1910 1911
	  time_benefit = base_time - time
	    + devirtualization_time_bonus (node, known_csts, known_binfos)
1912
	    + hint_time_bonus (hints)
1913 1914
	    + removable_params_cost + emc;

1915 1916 1917 1918 1919 1920 1921 1922
	  gcc_checking_assert (size >=0);
	  /* The inliner-heuristics based estimates may think that in certain
	     contexts some functions do not have any size at all but we want
	     all specializations to have at least a tiny cost, not least not to
	     divide by zero.  */
	  if (size == 0)
	    size = 1;

1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935
	  if (dump_file && (dump_flags & TDF_DETAILS))
	    {
	      fprintf (dump_file, " - estimates for value ");
	      print_ipcp_constant_value (dump_file, val->value);
	      fprintf (dump_file, " for parameter ");
	      print_generic_expr (dump_file, ipa_get_param (info, i), 0);
	      fprintf (dump_file, ": time_benefit: %i, size: %i\n",
		       time_benefit, size);
	    }

	  val->local_time_benefit = time_benefit;
	  val->local_size_cost = size;
	}
1936 1937
      known_binfos[i] = NULL_TREE;
      known_csts[i] = NULL_TREE;
1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948
    }

  for (i = 0; i < count ; i++)
    {
      struct ipcp_param_lattices *plats = ipa_get_parm_lattices (info, i);
      struct ipa_agg_jump_function *ajf;
      struct ipcp_agg_lattice *aglat;

      if (plats->aggs_bottom || !plats->aggs)
	continue;

1949
      ajf = &known_aggs[i];
1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966
      for (aglat = plats->aggs; aglat; aglat = aglat->next)
	{
	  struct ipcp_value *val;
	  if (aglat->bottom || !aglat->values
	      /* If the following is true, the one value is in known_aggs.  */
	      || (!plats->aggs_contain_variable
		  && ipa_lat_is_single_const (aglat)))
	    continue;

	  for (val = aglat->values; val; val = val->next)
	    {
	      int time, size, time_benefit;
	      struct ipa_agg_jf_item item;
	      inline_hints hints;

	      item.offset = aglat->offset;
	      item.value = val->value;
1967
	      vec_safe_push (ajf->items, item);
1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992

	      estimate_ipcp_clone_size_and_time (node, known_csts, known_binfos,
						 known_aggs_ptrs, &size, &time,
						 &hints);
	      time_benefit = base_time - time
		+ devirtualization_time_bonus (node, known_csts, known_binfos)
		+ hint_time_bonus (hints);
	      gcc_checking_assert (size >=0);
	      if (size == 0)
		size = 1;

	      if (dump_file && (dump_flags & TDF_DETAILS))
		{
		  fprintf (dump_file, " - estimates for value ");
		  print_ipcp_constant_value (dump_file, val->value);
		  fprintf (dump_file, " for parameter ");
		  print_generic_expr (dump_file, ipa_get_param (info, i), 0);
		  fprintf (dump_file, "[%soffset: " HOST_WIDE_INT_PRINT_DEC
				       "]: time_benefit: %i, size: %i\n",
				       plats->aggs_by_ref ? "ref " : "",
				       aglat->offset, time_benefit, size);
		}

	      val->local_time_benefit = time_benefit;
	      val->local_size_cost = size;
1993
	      ajf->items->pop ();
1994 1995 1996 1997 1998
	    }
	}
    }

  for (i = 0; i < count ; i++)
1999
    vec_free (known_aggs[i].items);
2000

2001 2002 2003 2004
  known_csts.release ();
  known_binfos.release ();
  known_aggs.release ();
  known_aggs_ptrs.release ();
2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043
}


/* Add value CUR_VAL and all yet-unsorted values it is dependent on to the
   topological sort of values.  */

static void
add_val_to_toposort (struct ipcp_value *cur_val)
{
  static int dfs_counter = 0;
  static struct ipcp_value *stack;
  struct ipcp_value_source *src;

  if (cur_val->dfs)
    return;

  dfs_counter++;
  cur_val->dfs = dfs_counter;
  cur_val->low_link = dfs_counter;

  cur_val->topo_next = stack;
  stack = cur_val;
  cur_val->on_stack = true;

  for (src = cur_val->sources; src; src = src->next)
    if (src->val)
      {
	if (src->val->dfs == 0)
	  {
	    add_val_to_toposort (src->val);
	    if (src->val->low_link < cur_val->low_link)
	      cur_val->low_link = src->val->low_link;
	  }
	else if (src->val->on_stack
		 && src->val->dfs < cur_val->low_link)
	  cur_val->low_link = src->val->dfs;
      }

  if (cur_val->dfs == cur_val->low_link)
2044
    {
2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059
      struct ipcp_value *v, *scc_list = NULL;

      do
	{
	  v = stack;
	  stack = v->topo_next;
	  v->on_stack = false;

	  v->scc_next = scc_list;
	  scc_list = v;
	}
      while (v != cur_val);

      cur_val->topo_next = values_topo;
      values_topo = cur_val;
2060
    }
Razya Ladelsky committed
2061 2062
}

2063 2064 2065 2066 2067
/* Add all values in lattices associated with NODE to the topological sort if
   they are not there yet.  */

static void
add_all_node_vals_to_toposort (struct cgraph_node *node)
Razya Ladelsky committed
2068
{
2069 2070 2071 2072 2073
  struct ipa_node_params *info = IPA_NODE_REF (node);
  int i, count = ipa_get_param_count (info);

  for (i = 0; i < count ; i++)
    {
2074 2075 2076
      struct ipcp_param_lattices *plats = ipa_get_parm_lattices (info, i);
      struct ipcp_lattice *lat = &plats->itself;
      struct ipcp_agg_lattice *aglat;
2077 2078
      struct ipcp_value *val;

2079 2080 2081 2082 2083 2084 2085 2086 2087
      if (!lat->bottom)
	for (val = lat->values; val; val = val->next)
	  add_val_to_toposort (val);

      if (!plats->aggs_bottom)
	for (aglat = plats->aggs; aglat; aglat = aglat->next)
	  if (!aglat->bottom)
	    for (val = aglat->values; val; val = val->next)
	      add_val_to_toposort (val);
2088
    }
Razya Ladelsky committed
2089 2090
}

2091 2092 2093 2094
/* One pass of constants propagation along the call graph edges, from callers
   to callees (requires topological ordering in TOPO), iterate over strongly
   connected components.  */

Razya Ladelsky committed
2095
static void
2096
propagate_constants_topo (struct topo_info *topo)
Razya Ladelsky committed
2097
{
2098
  int i;
Razya Ladelsky committed
2099

2100
  for (i = topo->nnodes - 1; i >= 0; i--)
Razya Ladelsky committed
2101
    {
2102 2103 2104 2105
      struct cgraph_node *v, *node = topo->order[i];
      struct ipa_dfs_info *node_dfs_info;

      if (!cgraph_function_with_gimple_body_p (node))
2106
	continue;
2107

2108
      node_dfs_info = (struct ipa_dfs_info *) node->symbol.aux;
2109 2110 2111 2112 2113 2114
      /* First, iteratively propagate within the strongly connected component
	 until all lattices stabilize.  */
      v = node_dfs_info->next_cycle;
      while (v)
	{
	  push_node_to_stack (topo, v);
2115
	  v = ((struct ipa_dfs_info *) v->symbol.aux)->next_cycle;
2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143
	}

      v = node;
      while (v)
	{
	  struct cgraph_edge *cs;

	  for (cs = v->callees; cs; cs = cs->next_callee)
	    if (edge_within_scc (cs)
		&& propagate_constants_accross_call (cs))
	      push_node_to_stack (topo, cs->callee);
	  v = pop_node_from_stack (topo);
	}

      /* Afterwards, propagate along edges leading out of the SCC, calculates
	 the local effects of the discovered constants and all valid values to
	 their topological sort.  */
      v = node;
      while (v)
	{
	  struct cgraph_edge *cs;

	  estimate_local_effects (v);
	  add_all_node_vals_to_toposort (v);
	  for (cs = v->callees; cs; cs = cs->next_callee)
	    if (!edge_within_scc (cs))
	      propagate_constants_accross_call (cs);

2144
	  v = ((struct ipa_dfs_info *) v->symbol.aux)->next_cycle;
2145
	}
Razya Ladelsky committed
2146 2147 2148
    }
}

2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162

/* Return the sum of A and B if none of them is bigger than INT_MAX/2, return
   the bigger one if otherwise.  */

static int
safe_add (int a, int b)
{
  if (a > INT_MAX/2 || b > INT_MAX/2)
    return a > b ? a : b;
  else
    return a + b;
}


2163
/* Propagate the estimated effects of individual values along the topological
Joseph Myers committed
2164
   from the dependent values to those they depend on.  */
2165

Razya Ladelsky committed
2166
static void
2167
propagate_effects (void)
Razya Ladelsky committed
2168
{
2169
  struct ipcp_value *base;
Razya Ladelsky committed
2170

2171
  for (base = values_topo; base; base = base->topo_next)
Razya Ladelsky committed
2172
    {
2173 2174 2175 2176 2177 2178
      struct ipcp_value_source *src;
      struct ipcp_value *val;
      int time = 0, size = 0;

      for (val = base; val; val = val->scc_next)
	{
2179 2180 2181
	  time = safe_add (time,
			   val->local_time_benefit + val->prop_time_benefit);
	  size = safe_add (size, val->local_size_cost + val->prop_size_cost);
2182 2183 2184 2185 2186 2187 2188
	}

      for (val = base; val; val = val->scc_next)
	for (src = val->sources; src; src = src->next)
	  if (src->val
	      && cgraph_maybe_hot_edge_p (src->cs))
	    {
2189 2190 2191 2192
	      src->val->prop_time_benefit = safe_add (time,
						src->val->prop_time_benefit);
	      src->val->prop_size_cost = safe_add (size,
						   src->val->prop_size_cost);
2193
	    }
Razya Ladelsky committed
2194 2195 2196
    }
}

2197 2198 2199 2200

/* Propagate constants, binfos and their effects from the summaries
   interprocedurally.  */

Razya Ladelsky committed
2201
static void
2202
ipcp_propagate_stage (struct topo_info *topo)
Razya Ladelsky committed
2203 2204 2205
{
  struct cgraph_node *node;

2206 2207 2208 2209 2210 2211 2212 2213 2214 2215 2216 2217 2218 2219
  if (dump_file)
    fprintf (dump_file, "\n Propagating constants:\n\n");

  if (in_lto_p)
    ipa_update_after_lto_read ();


  FOR_EACH_DEFINED_FUNCTION (node)
  {
    struct ipa_node_params *info = IPA_NODE_REF (node);

    determine_versionability (node);
    if (cgraph_function_with_gimple_body_p (node))
      {
2220
	info->lattices = XCNEWVEC (struct ipcp_param_lattices,
2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 2243 2244 2245 2246 2247 2248 2249 2250 2251 2252 2253 2254 2255
				   ipa_get_param_count (info));
	initialize_node_lattices (node);
      }
    if (node->count > max_count)
      max_count = node->count;
    overall_size += inline_summary (node)->self_size;
  }

  max_new_size = overall_size;
  if (max_new_size < PARAM_VALUE (PARAM_LARGE_UNIT_INSNS))
    max_new_size = PARAM_VALUE (PARAM_LARGE_UNIT_INSNS);
  max_new_size += max_new_size * PARAM_VALUE (PARAM_IPCP_UNIT_GROWTH) / 100 + 1;

  if (dump_file)
    fprintf (dump_file, "\noverall_size: %li, max_new_size: %li\n",
	     overall_size, max_new_size);

  propagate_constants_topo (topo);
#ifdef ENABLE_CHECKING
  ipcp_verify_propagated_values ();
#endif
  propagate_effects ();

  if (dump_file)
    {
      fprintf (dump_file, "\nIPA lattices after all propagation:\n");
      print_all_lattices (dump_file, (dump_flags & TDF_DETAILS), true);
    }
}

/* Discover newly direct outgoing edges from NODE which is a new clone with
   known KNOWN_VALS and make them direct.  */

static void
ipcp_discover_new_direct_edges (struct cgraph_node *node,
2256
				vec<tree> known_vals)
2257 2258
{
  struct cgraph_edge *ie, *next_ie;
2259
  bool found = false;
2260 2261 2262

  for (ie = node->indirect_calls; ie; ie = next_ie)
    {
2263
      tree target;
2264 2265

      next_ie = ie->next_callee;
2266
      target = ipa_get_indirect_edge_target (ie, known_vals, vNULL, vNULL);
2267
      if (target)
2268 2269 2270 2271
	{
	  ipa_make_edge_direct_to_target (ie, target);
	  found = true;
	}
2272
    }
2273 2274 2275
  /* Turning calls to direct calls will improve overall summary.  */
  if (found)
    inline_update_overall_summary (node);
2276 2277 2278 2279 2280
}

/* Vector of pointers which for linked lists of clones of an original crgaph
   edge. */

2281
static vec<cgraph_edge_p> next_edge_clone;
2282 2283 2284 2285

static inline void
grow_next_edge_clone_vector (void)
{
2286
  if (next_edge_clone.length ()
2287
      <=  (unsigned) cgraph_edge_max_uid)
2288
    next_edge_clone.safe_grow_cleared (cgraph_edge_max_uid + 1);
2289 2290 2291 2292 2293 2294 2295 2296 2297 2298
}

/* Edge duplication hook to grow the appropriate linked list in
   next_edge_clone. */

static void
ipcp_edge_duplication_hook (struct cgraph_edge *src, struct cgraph_edge *dst,
			    __attribute__((unused)) void *data)
{
  grow_next_edge_clone_vector ();
2299 2300
  next_edge_clone[dst->uid] = next_edge_clone[src->uid];
  next_edge_clone[src->uid] = dst;
2301 2302
}

2303 2304
/* See if NODE is a clone with a known aggregate value at a given OFFSET of a
   parameter with the given INDEX.  */
2305

2306 2307 2308
static tree
get_clone_agg_value (struct cgraph_node *node, HOST_WIDEST_INT offset,
		     int index)
2309
{
2310 2311 2312 2313 2314 2315 2316 2317 2318 2319 2320
  struct ipa_agg_replacement_value *aggval;

  aggval = ipa_get_agg_replacements_for_node (node);
  while (aggval)
    {
      if (aggval->offset == offset
	  && aggval->index == index)
	return aggval->value;
      aggval = aggval->next;
    }
  return NULL_TREE;
2321 2322 2323 2324 2325 2326 2327 2328 2329
}

/* Return true if edge CS does bring about the value described by SRC.  */

static bool
cgraph_edge_brings_value_p (struct cgraph_edge *cs,
			    struct ipcp_value_source *src)
{
  struct ipa_node_params *caller_info = IPA_NODE_REF (cs->caller);
2330
  struct ipa_node_params *dst_info = IPA_NODE_REF (cs->callee);
2331

2332
  if ((dst_info->ipcp_orig_node && !dst_info->is_all_contexts_clone)
2333 2334 2335 2336 2337 2338 2339
      || caller_info->node_dead)
    return false;
  if (!src->val)
    return true;

  if (caller_info->ipcp_orig_node)
    {
2340 2341
      tree t;
      if (src->offset == -1)
2342
	t = caller_info->known_vals[src->index];
2343 2344
      else
	t = get_clone_agg_value (cs->caller, src->offset, src->index);
2345 2346 2347 2348
      return (t != NULL_TREE
	      && values_equal_for_ipcp_p (src->val->value, t));
    }
  else
Razya Ladelsky committed
2349
    {
2350 2351 2352 2353 2354 2355 2356
      struct ipcp_agg_lattice *aglat;
      struct ipcp_param_lattices *plats = ipa_get_parm_lattices (caller_info,
								 src->index);
      if (src->offset == -1)
	return (ipa_lat_is_single_const (&plats->itself)
		&& values_equal_for_ipcp_p (src->val->value,
					    plats->itself.values->value));
2357
      else
2358 2359 2360 2361 2362 2363 2364 2365 2366 2367
	{
	  if (plats->aggs_bottom || plats->aggs_contain_variable)
	    return false;
	  for (aglat = plats->aggs; aglat; aglat = aglat->next)
	    if (aglat->offset == src->offset)
	      return  (ipa_lat_is_single_const (aglat)
		       && values_equal_for_ipcp_p (src->val->value,
						   aglat->values->value));
	}
      return false;
2368 2369 2370
    }
}

2371 2372 2373 2374 2375
/* Get the next clone in the linked list of clones of an edge.  */

static inline struct cgraph_edge *
get_next_cgraph_edge_clone (struct cgraph_edge *cs)
{
2376
  return next_edge_clone[cs->uid];
2377 2378
}

2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395
/* Given VAL, iterate over all its sources and if they still hold, add their
   edge frequency and their number into *FREQUENCY and *CALLER_COUNT
   respectively.  */

static bool
get_info_about_necessary_edges (struct ipcp_value *val, int *freq_sum,
				gcov_type *count_sum, int *caller_count)
{
  struct ipcp_value_source *src;
  int freq = 0, count = 0;
  gcov_type cnt = 0;
  bool hot = false;

  for (src = val->sources; src; src = src->next)
    {
      struct cgraph_edge *cs = src->cs;
      while (cs)
Razya Ladelsky committed
2396
	{
2397 2398 2399 2400 2401 2402 2403 2404
	  if (cgraph_edge_brings_value_p (cs, src))
	    {
	      count++;
	      freq += cs->frequency;
	      cnt += cs->count;
	      hot |= cgraph_maybe_hot_edge_p (cs);
	    }
	  cs = get_next_cgraph_edge_clone (cs);
Razya Ladelsky committed
2405 2406
	}
    }
2407 2408 2409 2410 2411

  *freq_sum = freq;
  *count_sum = cnt;
  *caller_count = count;
  return hot;
Razya Ladelsky committed
2412 2413
}

2414 2415 2416
/* Return a vector of incoming edges that do bring value VAL.  It is assumed
   their number is known and equal to CALLER_COUNT.  */

2417
static vec<cgraph_edge_p> 
2418
gather_edges_for_value (struct ipcp_value *val, int caller_count)
Razya Ladelsky committed
2419
{
2420
  struct ipcp_value_source *src;
2421
  vec<cgraph_edge_p> ret;
2422

2423
  ret.create (caller_count);
2424 2425 2426 2427 2428 2429
  for (src = val->sources; src; src = src->next)
    {
      struct cgraph_edge *cs = src->cs;
      while (cs)
	{
	  if (cgraph_edge_brings_value_p (cs, src))
2430
	    ret.quick_push (cs);
2431 2432 2433 2434 2435
	  cs = get_next_cgraph_edge_clone (cs);
	}
    }

  return ret;
Razya Ladelsky committed
2436 2437
}

2438 2439 2440
/* Construct a replacement map for a know VALUE for a formal parameter PARAM.
   Return it or NULL if for some reason it cannot be created.  */

Razya Ladelsky committed
2441
static struct ipa_replace_map *
2442
get_replacement_map (tree value, tree parm)
Razya Ladelsky committed
2443
{
2444
  tree req_type = TREE_TYPE (parm);
Razya Ladelsky committed
2445 2446
  struct ipa_replace_map *replace_map;

2447
  if (!useless_type_conversion_p (req_type, TREE_TYPE (value)))
2448
    {
2449 2450 2451 2452 2453
      if (fold_convertible_p (req_type, value))
	value = fold_build1 (NOP_EXPR, req_type, value);
      else if (TYPE_SIZE (req_type) == TYPE_SIZE (TREE_TYPE (value)))
	value = fold_build1 (VIEW_CONVERT_EXPR, req_type, value);
      else
2454
	{
2455 2456 2457 2458 2459 2460 2461 2462 2463
	  if (dump_file)
	    {
	      fprintf (dump_file, "    const ");
	      print_generic_expr (dump_file, value, 0);
	      fprintf (dump_file, "  can't be converted to param ");
	      print_generic_expr (dump_file, parm, 0);
	      fprintf (dump_file, "\n");
	    }
	  return NULL;
2464 2465
	}
    }
2466

2467
  replace_map = ggc_alloc_ipa_replace_map ();
2468 2469
  if (dump_file)
    {
2470 2471
      fprintf (dump_file, "    replacing param ");
      print_generic_expr (dump_file, parm, 0);
2472
      fprintf (dump_file, " with const ");
2473
      print_generic_expr (dump_file, value, 0);
2474 2475
      fprintf (dump_file, "\n");
    }
2476 2477
  replace_map->old_tree = parm;
  replace_map->new_tree = value;
2478 2479
  replace_map->replace_p = true;
  replace_map->ref_p = false;
Razya Ladelsky committed
2480 2481 2482 2483

  return replace_map;
}

2484
/* Dump new profiling counts */
Razya Ladelsky committed
2485 2486

static void
2487 2488
dump_profile_updates (struct cgraph_node *orig_node,
		      struct cgraph_node *new_node)
Razya Ladelsky committed
2489
{
2490
  struct cgraph_edge *cs;
Razya Ladelsky committed
2491

2492 2493 2494 2495 2496 2497 2498 2499 2500 2501 2502 2503 2504 2505
  fprintf (dump_file, "    setting count of the specialized node to "
	   HOST_WIDE_INT_PRINT_DEC "\n", (HOST_WIDE_INT) new_node->count);
  for (cs = new_node->callees; cs ; cs = cs->next_callee)
    fprintf (dump_file, "      edge to %s has count "
	     HOST_WIDE_INT_PRINT_DEC "\n",
	     cgraph_node_name (cs->callee), (HOST_WIDE_INT) cs->count);

  fprintf (dump_file, "    setting count of the original node to "
	   HOST_WIDE_INT_PRINT_DEC "\n", (HOST_WIDE_INT) orig_node->count);
  for (cs = orig_node->callees; cs ; cs = cs->next_callee)
    fprintf (dump_file, "      edge to %s is left with "
	     HOST_WIDE_INT_PRINT_DEC "\n",
	     cgraph_node_name (cs->callee), (HOST_WIDE_INT) cs->count);
}
2506

2507 2508
/* After a specialized NEW_NODE version of ORIG_NODE has been created, update
   their profile information to reflect this.  */
Razya Ladelsky committed
2509 2510

static void
2511 2512
update_profiling_info (struct cgraph_node *orig_node,
		       struct cgraph_node *new_node)
Razya Ladelsky committed
2513 2514
{
  struct cgraph_edge *cs;
2515 2516 2517 2518 2519 2520
  struct caller_statistics stats;
  gcov_type new_sum, orig_sum;
  gcov_type remainder, orig_node_count = orig_node->count;

  if (orig_node_count == 0)
    return;
Razya Ladelsky committed
2521

2522 2523 2524 2525 2526 2527 2528 2529
  init_caller_stats (&stats);
  cgraph_for_node_and_aliases (orig_node, gather_caller_stats, &stats, false);
  orig_sum = stats.count_sum;
  init_caller_stats (&stats);
  cgraph_for_node_and_aliases (new_node, gather_caller_stats, &stats, false);
  new_sum = stats.count_sum;

  if (orig_node_count < orig_sum + new_sum)
Razya Ladelsky committed
2530
    {
2531 2532 2533 2534 2535 2536 2537 2538 2539 2540 2541 2542 2543
      if (dump_file)
	fprintf (dump_file, "    Problem: node %s/%i has too low count "
		 HOST_WIDE_INT_PRINT_DEC " while the sum of incoming "
		 "counts is " HOST_WIDE_INT_PRINT_DEC "\n",
		 cgraph_node_name (orig_node), orig_node->uid,
		 (HOST_WIDE_INT) orig_node_count,
		 (HOST_WIDE_INT) (orig_sum + new_sum));

      orig_node_count = (orig_sum + new_sum) * 12 / 10;
      if (dump_file)
	fprintf (dump_file, "      proceeding by pretending it was "
		 HOST_WIDE_INT_PRINT_DEC "\n",
		 (HOST_WIDE_INT) orig_node_count);
Razya Ladelsky committed
2544
    }
2545 2546 2547 2548 2549 2550 2551

  new_node->count = new_sum;
  remainder = orig_node_count - new_sum;
  orig_node->count = remainder;

  for (cs = new_node->callees; cs ; cs = cs->next_callee)
    if (cs->frequency)
2552 2553
      cs->count = cs->count * (new_sum * REG_BR_PROB_BASE
			       / orig_node_count) / REG_BR_PROB_BASE;
2554 2555 2556 2557
    else
      cs->count = 0;

  for (cs = orig_node->callees; cs ; cs = cs->next_callee)
2558 2559
    cs->count = cs->count * (remainder * REG_BR_PROB_BASE
			     / orig_node_count) / REG_BR_PROB_BASE;
2560 2561 2562

  if (dump_file)
    dump_profile_updates (orig_node, new_node);
Razya Ladelsky committed
2563 2564
}

2565 2566 2567 2568 2569 2570 2571 2572
/* Update the respective profile of specialized NEW_NODE and the original
   ORIG_NODE after additional edges with cumulative count sum REDIRECTED_SUM
   have been redirected to the specialized version.  */

static void
update_specialized_profile (struct cgraph_node *new_node,
			    struct cgraph_node *orig_node,
			    gcov_type redirected_sum)
2573
{
2574
  struct cgraph_edge *cs;
2575
  gcov_type new_node_count, orig_node_count = orig_node->count;
2576

2577 2578 2579 2580 2581
  if (dump_file)
    fprintf (dump_file, "    the sum of counts of redirected  edges is "
	     HOST_WIDE_INT_PRINT_DEC "\n", (HOST_WIDE_INT) redirected_sum);
  if (orig_node_count == 0)
    return;
2582

2583
  gcc_assert (orig_node_count >= redirected_sum);
2584

2585 2586 2587
  new_node_count = new_node->count;
  new_node->count += redirected_sum;
  orig_node->count -= redirected_sum;
2588

2589 2590 2591 2592 2593
  for (cs = new_node->callees; cs ; cs = cs->next_callee)
    if (cs->frequency)
      cs->count += cs->count * redirected_sum / new_node_count;
    else
      cs->count = 0;
2594

2595 2596
  for (cs = orig_node->callees; cs ; cs = cs->next_callee)
    {
2597 2598
      gcov_type dec = cs->count * (redirected_sum * REG_BR_PROB_BASE
				   / orig_node_count) / REG_BR_PROB_BASE;
2599 2600 2601 2602 2603
      if (dec < cs->count)
	cs->count -= dec;
      else
	cs->count = 0;
    }
2604

2605 2606
  if (dump_file)
    dump_profile_updates (orig_node, new_node);
2607 2608
}

2609 2610
/* Create a specialized version of NODE with known constants and types of
   parameters in KNOWN_VALS and redirect all edges in CALLERS to it.  */
2611

2612 2613
static struct cgraph_node *
create_specialized_node (struct cgraph_node *node,
2614
			 vec<tree> known_vals,
2615
			 struct ipa_agg_replacement_value *aggvals,
2616
			 vec<cgraph_edge_p> callers)
2617
{
2618
  struct ipa_node_params *new_info, *info = IPA_NODE_REF (node);
2619
  vec<ipa_replace_map_p, va_gc> *replace_trees = NULL;
2620 2621 2622
  struct cgraph_node *new_node;
  int i, count = ipa_get_param_count (info);
  bitmap args_to_skip;
2623

2624 2625 2626
  gcc_assert (!info->ipcp_orig_node);

  if (node->local.can_change_signature)
2627
    {
2628 2629 2630
      args_to_skip = BITMAP_GGC_ALLOC ();
      for (i = 0; i < count; i++)
	{
2631
	  tree t = known_vals[i];
2632 2633 2634 2635 2636 2637 2638

	  if ((t && TREE_CODE (t) != TREE_BINFO)
	      || !ipa_is_param_used (info, i))
	    bitmap_set_bit (args_to_skip, i);
	}
    }
  else
2639 2640 2641 2642 2643
    {
      args_to_skip = NULL;
      if (dump_file && (dump_flags & TDF_DETAILS))
	fprintf (dump_file, "      cannot change function signature\n");
    }
2644 2645 2646

  for (i = 0; i < count ; i++)
    {
2647
      tree t = known_vals[i];
2648 2649 2650 2651 2652 2653
      if (t && TREE_CODE (t) != TREE_BINFO)
	{
	  struct ipa_replace_map *replace_map;

	  replace_map = get_replacement_map (t, ipa_get_param (info, i));
	  if (replace_map)
2654
	    vec_safe_push (replace_trees, replace_map);
2655
	}
2656 2657
    }

2658 2659
  new_node = cgraph_create_virtual_clone (node, callers, replace_trees,
					  args_to_skip, "constprop");
2660
  ipa_set_node_agg_value_chain (new_node, aggvals);
2661
  if (dump_file && (dump_flags & TDF_DETAILS))
2662 2663 2664 2665 2666 2667
    {
      fprintf (dump_file, "     the new node is %s/%i.\n",
	       cgraph_node_name (new_node), new_node->uid);
      if (aggvals)
	ipa_dump_agg_replacement_values (dump_file, aggvals);
    }
2668 2669
  gcc_checking_assert (ipa_node_params_vector.exists ()
		       && (ipa_node_params_vector.length ()
2670 2671 2672 2673 2674
			   > (unsigned) cgraph_max_uid));
  update_profiling_info (node, new_node);
  new_info = IPA_NODE_REF (new_node);
  new_info->ipcp_orig_node = node;
  new_info->known_vals = known_vals;
2675

2676 2677
  ipcp_discover_new_direct_edges (new_node, known_vals);

2678
  callers.release ();
2679
  return new_node;
2680 2681
}

2682 2683 2684
/* Given a NODE, and a subset of its CALLERS, try to populate blanks slots in
   KNOWN_VALS with constants and types that are also known for all of the
   CALLERS.  */
2685 2686

static void
2687
find_more_scalar_values_for_callers_subset (struct cgraph_node *node,
2688 2689
					    vec<tree> known_vals,
					    vec<cgraph_edge_p> callers)
2690 2691
{
  struct ipa_node_params *info = IPA_NODE_REF (node);
2692
  int i, count = ipa_get_param_count (info);
2693

2694
  for (i = 0; i < count ; i++)
2695
    {
2696 2697 2698
      struct cgraph_edge *cs;
      tree newval = NULL_TREE;
      int j;
2699

2700
      if (ipa_get_scalar_lat (info, i)->bottom || known_vals[i])
2701 2702
	continue;

2703
      FOR_EACH_VEC_ELT (callers, j, cs)
2704
	{
2705 2706
	  struct ipa_jump_func *jump_func;
	  tree t;
2707

2708 2709 2710 2711 2712
          if (i >= ipa_get_cs_argument_count (IPA_EDGE_REF (cs)))
            {
              newval = NULL_TREE;
              break;
            }
2713 2714 2715 2716 2717
	  jump_func = ipa_get_ith_jump_func (IPA_EDGE_REF (cs), i);
	  t = ipa_value_from_jfunc (IPA_NODE_REF (cs->caller), jump_func);
	  if (!t
	      || (newval
		  && !values_equal_for_ipcp_p (t, newval)))
2718
	    {
2719 2720
	      newval = NULL_TREE;
	      break;
2721
	    }
2722 2723
	  else
	    newval = t;
2724 2725
	}

2726 2727 2728 2729
      if (newval)
	{
	  if (dump_file && (dump_flags & TDF_DETAILS))
	    {
2730
	      fprintf (dump_file, "    adding an extra known scalar value ");
2731 2732 2733 2734 2735
	      print_ipcp_constant_value (dump_file, newval);
	      fprintf (dump_file, " for parameter ");
	      print_generic_expr (dump_file, ipa_get_param (info, i), 0);
	      fprintf (dump_file, "\n");
	    }
2736

2737
	  known_vals[i] = newval;
2738
	}
2739 2740 2741
    }
}

2742 2743 2744
/* Go through PLATS and create a vector of values consisting of values and
   offsets (minus OFFSET) of lattices that contain only a single value.  */

2745
static vec<ipa_agg_jf_item_t>
2746 2747
copy_plats_to_inter (struct ipcp_param_lattices *plats, HOST_WIDE_INT offset)
{
2748
  vec<ipa_agg_jf_item_t> res = vNULL;
2749 2750

  if (!plats->aggs || plats->aggs_contain_variable || plats->aggs_bottom)
2751
    return vNULL;
2752 2753 2754 2755 2756 2757 2758

  for (struct ipcp_agg_lattice *aglat = plats->aggs; aglat; aglat = aglat->next)
    if (ipa_lat_is_single_const (aglat))
      {
	struct ipa_agg_jf_item ti;
	ti.offset = aglat->offset - offset;
	ti.value = aglat->values->value;
2759
	res.safe_push (ti);
2760 2761 2762 2763 2764 2765 2766 2767 2768
      }
  return res;
}

/* Intersect all values in INTER with single value lattices in PLATS (while
   subtracting OFFSET).  */

static void
intersect_with_plats (struct ipcp_param_lattices *plats,
2769
		      vec<ipa_agg_jf_item_t> *inter,
2770 2771 2772 2773 2774 2775 2776 2777
		      HOST_WIDE_INT offset)
{
  struct ipcp_agg_lattice *aglat;
  struct ipa_agg_jf_item *item;
  int k;

  if (!plats->aggs || plats->aggs_contain_variable || plats->aggs_bottom)
    {
2778
      inter->release ();
2779 2780 2781 2782
      return;
    }

  aglat = plats->aggs;
2783
  FOR_EACH_VEC_ELT (*inter, k, item)
2784 2785 2786 2787 2788 2789 2790 2791 2792 2793 2794 2795 2796 2797 2798 2799 2800 2801 2802 2803 2804 2805 2806 2807 2808
    {
      bool found = false;
      if (!item->value)
	continue;
      while (aglat)
	{
	  if (aglat->offset - offset > item->offset)
	    break;
	  if (aglat->offset - offset == item->offset)
	    {
	      gcc_checking_assert (item->value);
	      if (values_equal_for_ipcp_p (item->value, aglat->values->value))
		found = true;
	      break;
	    }
	  aglat = aglat->next;
	}
      if (!found)
	item->value = NULL_TREE;
    }
}

/* Copy agggregate replacement values of NODE (which is an IPA-CP clone) to the
   vector result while subtracting OFFSET from the individual value offsets.  */

2809
static vec<ipa_agg_jf_item_t>
2810 2811
agg_replacements_to_vector (struct cgraph_node *node, int index,
			    HOST_WIDE_INT offset)
2812 2813
{
  struct ipa_agg_replacement_value *av;
2814
  vec<ipa_agg_jf_item_t> res = vNULL;
2815 2816

  for (av = ipa_get_agg_replacements_for_node (node); av; av = av->next)
2817 2818
    if (av->index == index
	&& (av->offset - offset) >= 0)
2819 2820 2821 2822 2823
    {
      struct ipa_agg_jf_item item;
      gcc_checking_assert (av->value);
      item.offset = av->offset - offset;
      item.value = av->value;
2824
      res.safe_push (item);
2825 2826 2827 2828 2829 2830 2831 2832 2833 2834 2835
    }

  return res;
}

/* Intersect all values in INTER with those that we have already scheduled to
   be replaced in parameter number INDEX of NODE, which is an IPA-CP clone
   (while subtracting OFFSET).  */

static void
intersect_with_agg_replacements (struct cgraph_node *node, int index,
2836
				 vec<ipa_agg_jf_item_t> *inter,
2837 2838 2839 2840 2841 2842 2843 2844 2845
				 HOST_WIDE_INT offset)
{
  struct ipa_agg_replacement_value *srcvals;
  struct ipa_agg_jf_item *item;
  int i;

  srcvals = ipa_get_agg_replacements_for_node (node);
  if (!srcvals)
    {
2846
      inter->release ();
2847 2848 2849
      return;
    }

2850
  FOR_EACH_VEC_ELT (*inter, i, item)
2851 2852 2853 2854 2855 2856 2857 2858 2859 2860 2861 2862 2863 2864 2865 2866 2867 2868 2869 2870 2871
    {
      struct ipa_agg_replacement_value *av;
      bool found = false;
      if (!item->value)
	continue;
      for (av = srcvals; av; av = av->next)
	{
	  gcc_checking_assert (av->value);
	  if (av->index == index
	      && av->offset - offset == item->offset)
	    {
	      if (values_equal_for_ipcp_p (item->value, av->value))
		found = true;
	      break;
	    }
	}
      if (!found)
	item->value = NULL_TREE;
    }
}

2872 2873 2874 2875 2876 2877 2878 2879 2880 2881 2882 2883 2884 2885 2886 2887 2888 2889 2890 2891 2892 2893 2894 2895 2896 2897
/* Intersect values in INTER with aggregate values that come along edge CS to
   parameter number INDEX and return it.  If INTER does not actually exist yet,
   copy all incoming values to it.  If we determine we ended up with no values
   whatsoever, return a released vector.  */

static vec<ipa_agg_jf_item_t>
intersect_aggregates_with_edge (struct cgraph_edge *cs, int index,
				vec<ipa_agg_jf_item_t> inter)
{
  struct ipa_jump_func *jfunc;
  jfunc = ipa_get_ith_jump_func (IPA_EDGE_REF (cs), index);
  if (jfunc->type == IPA_JF_PASS_THROUGH
      && ipa_get_jf_pass_through_operation (jfunc) == NOP_EXPR)
    {
      struct ipa_node_params *caller_info = IPA_NODE_REF (cs->caller);
      int src_idx = ipa_get_jf_pass_through_formal_id (jfunc);

      if (caller_info->ipcp_orig_node)
	{
	  struct cgraph_node *orig_node = caller_info->ipcp_orig_node;
	  struct ipcp_param_lattices *orig_plats;
	  orig_plats = ipa_get_parm_lattices (IPA_NODE_REF (orig_node),
					      src_idx);
	  if (agg_pass_through_permissible_p (orig_plats, jfunc))
	    {
	      if (!inter.exists ())
2898
		inter = agg_replacements_to_vector (cs->caller, src_idx, 0);
2899 2900 2901 2902 2903 2904 2905 2906 2907 2908 2909 2910 2911 2912 2913 2914 2915 2916 2917 2918 2919 2920 2921 2922 2923 2924 2925 2926 2927 2928 2929 2930
	      else
		intersect_with_agg_replacements (cs->caller, src_idx,
						 &inter, 0);
	    }
	}
      else
	{
	  struct ipcp_param_lattices *src_plats;
	  src_plats = ipa_get_parm_lattices (caller_info, src_idx);
	  if (agg_pass_through_permissible_p (src_plats, jfunc))
	    {
	      /* Currently we do not produce clobber aggregate jump
		 functions, adjust when we do.  */
	      gcc_checking_assert (!jfunc->agg.items);
	      if (!inter.exists ())
		inter = copy_plats_to_inter (src_plats, 0);
	      else
		intersect_with_plats (src_plats, &inter, 0);
	    }
	}
    }
  else if (jfunc->type == IPA_JF_ANCESTOR
	   && ipa_get_jf_ancestor_agg_preserved (jfunc))
    {
      struct ipa_node_params *caller_info = IPA_NODE_REF (cs->caller);
      int src_idx = ipa_get_jf_ancestor_formal_id (jfunc);
      struct ipcp_param_lattices *src_plats;
      HOST_WIDE_INT delta = ipa_get_jf_ancestor_offset (jfunc);

      if (caller_info->ipcp_orig_node)
	{
	  if (!inter.exists ())
2931
	    inter = agg_replacements_to_vector (cs->caller, src_idx, delta);
2932
	  else
2933
	    intersect_with_agg_replacements (cs->caller, src_idx, &inter,
2934 2935 2936 2937 2938 2939 2940 2941 2942 2943 2944 2945 2946 2947 2948 2949 2950 2951 2952 2953 2954 2955 2956 2957 2958 2959 2960 2961 2962 2963 2964 2965 2966 2967 2968 2969 2970 2971 2972 2973 2974 2975 2976 2977 2978 2979 2980 2981 2982 2983 2984 2985 2986 2987 2988 2989 2990 2991 2992
					     delta);
	}
      else
	{
	  src_plats = ipa_get_parm_lattices (caller_info, src_idx);;
	  /* Currently we do not produce clobber aggregate jump
	     functions, adjust when we do.  */
	  gcc_checking_assert (!src_plats->aggs || !jfunc->agg.items);
	  if (!inter.exists ())
	    inter = copy_plats_to_inter (src_plats, delta);
	  else
	    intersect_with_plats (src_plats, &inter, delta);
	}
    }
  else if (jfunc->agg.items)
    {
      struct ipa_agg_jf_item *item;
      int k;

      if (!inter.exists ())
	for (unsigned i = 0; i < jfunc->agg.items->length (); i++)
	  inter.safe_push ((*jfunc->agg.items)[i]);
      else
	FOR_EACH_VEC_ELT (inter, k, item)
	  {
	    int l = 0;
	    bool found = false;;

	    if (!item->value)
	      continue;

	    while ((unsigned) l < jfunc->agg.items->length ())
	      {
		struct ipa_agg_jf_item *ti;
		ti = &(*jfunc->agg.items)[l];
		if (ti->offset > item->offset)
		  break;
		if (ti->offset == item->offset)
		  {
		    gcc_checking_assert (ti->value);
		    if (values_equal_for_ipcp_p (item->value,
						 ti->value))
		      found = true;
		    break;
		  }
		l++;
	      }
	    if (!found)
	      item->value = NULL;
	  }
    }
  else
    {
      inter.release();
      return vec<ipa_agg_jf_item_t>();
    }
  return inter;
}

2993 2994 2995 2996 2997
/* Look at edges in CALLERS and collect all known aggregate values that arrive
   from all of them.  */

static struct ipa_agg_replacement_value *
find_aggregate_values_for_callers_subset (struct cgraph_node *node,
2998
					  vec<cgraph_edge_p> callers)
2999
{
3000
  struct ipa_node_params *dest_info = IPA_NODE_REF (node);
3001 3002
  struct ipa_agg_replacement_value *res = NULL;
  struct cgraph_edge *cs;
3003
  int i, j, count = ipa_get_param_count (dest_info);
3004

3005
  FOR_EACH_VEC_ELT (callers, j, cs)
3006 3007 3008 3009 3010 3011 3012 3013 3014
    {
      int c = ipa_get_cs_argument_count (IPA_EDGE_REF (cs));
      if (c < count)
	count = c;
    }

  for (i = 0; i < count ; i++)
    {
      struct cgraph_edge *cs;
3015
      vec<ipa_agg_jf_item_t> inter = vNULL;
3016 3017 3018 3019 3020
      struct ipa_agg_jf_item *item;
      int j;

      /* Among other things, the following check should deal with all by_ref
	 mismatches.  */
3021
      if (ipa_get_parm_lattices (dest_info, i)->aggs_bottom)
3022 3023
	continue;

3024
      FOR_EACH_VEC_ELT (callers, j, cs)
3025
	{
3026
	  inter = intersect_aggregates_with_edge (cs, i, inter);
3027

3028
	  if (!inter.exists ())
3029 3030 3031
	    goto next_param;
	}

3032
      FOR_EACH_VEC_ELT (inter, j, item)
3033 3034 3035 3036 3037 3038 3039 3040 3041 3042 3043 3044 3045 3046 3047
	{
	  struct ipa_agg_replacement_value *v;

	  if (!item->value)
	    continue;

	  v = ggc_alloc_ipa_agg_replacement_value ();
	  v->index = i;
	  v->offset = item->offset;
	  v->value = item->value;
	  v->next = res;
	  res = v;
	}

    next_param:
3048 3049
      if (inter.exists ())
	inter.release ();
3050 3051 3052 3053 3054 3055 3056
    }
  return res;
}

/* Turn KNOWN_AGGS into a list of aggreate replacement values.  */

static struct ipa_agg_replacement_value *
3057
known_aggs_to_agg_replacement_list (vec<ipa_agg_jump_function_t> known_aggs)
3058 3059 3060 3061 3062 3063
{
  struct ipa_agg_replacement_value *res = NULL;
  struct ipa_agg_jump_function *aggjf;
  struct ipa_agg_jf_item *item;
  int i, j;

3064 3065
  FOR_EACH_VEC_ELT (known_aggs, i, aggjf)
    FOR_EACH_VEC_SAFE_ELT (aggjf->items, j, item)
3066 3067 3068 3069 3070 3071 3072 3073 3074 3075 3076 3077 3078 3079 3080 3081 3082 3083 3084 3085 3086 3087 3088 3089 3090 3091 3092 3093 3094 3095 3096 3097
      {
	struct ipa_agg_replacement_value *v;
	v = ggc_alloc_ipa_agg_replacement_value ();
	v->index = i;
	v->offset = item->offset;
	v->value = item->value;
	v->next = res;
	res = v;
      }
  return res;
}

/* Determine whether CS also brings all scalar values that the NODE is
   specialized for.  */

static bool
cgraph_edge_brings_all_scalars_for_node (struct cgraph_edge *cs,
					 struct cgraph_node *node)
{
  struct ipa_node_params *dest_info = IPA_NODE_REF (node);
  int count = ipa_get_param_count (dest_info);
  struct ipa_node_params *caller_info;
  struct ipa_edge_args *args;
  int i;

  caller_info = IPA_NODE_REF (cs->caller);
  args = IPA_EDGE_REF (cs);
  for (i = 0; i < count; i++)
    {
      struct ipa_jump_func *jump_func;
      tree val, t;

3098
      val = dest_info->known_vals[i];
3099 3100 3101 3102 3103 3104 3105 3106 3107 3108 3109 3110 3111 3112 3113 3114 3115 3116 3117
      if (!val)
	continue;

      if (i >= ipa_get_cs_argument_count (args))
	return false;
      jump_func = ipa_get_ith_jump_func (args, i);
      t = ipa_value_from_jfunc (caller_info, jump_func);
      if (!t || !values_equal_for_ipcp_p (val, t))
	return false;
    }
  return true;
}

/* Determine whether CS also brings all aggregate values that NODE is
   specialized for.  */
static bool
cgraph_edge_brings_all_agg_vals_for_node (struct cgraph_edge *cs,
					  struct cgraph_node *node)
{
3118
  struct ipa_node_params *orig_caller_info = IPA_NODE_REF (cs->caller);
3119
  struct ipa_agg_replacement_value *aggval;
3120
  int i, ec, count;
3121 3122

  aggval = ipa_get_agg_replacements_for_node (node);
3123 3124 3125 3126 3127 3128 3129 3130 3131 3132 3133 3134 3135 3136
  if (!aggval)
    return true;

  count = ipa_get_param_count (IPA_NODE_REF (node));
  ec = ipa_get_cs_argument_count (IPA_EDGE_REF (cs));
  if (ec < count)
    for (struct ipa_agg_replacement_value *av = aggval; av; av = av->next)
      if (aggval->index >= ec)
	return false;

  if (orig_caller_info->ipcp_orig_node)
    orig_caller_info = IPA_NODE_REF (orig_caller_info->ipcp_orig_node);

  for (i = 0; i < count; i++)
3137
    {
3138
      static vec<ipa_agg_jf_item_t> values = vec<ipa_agg_jf_item_t>();
3139
      struct ipcp_param_lattices *plats;
3140 3141 3142 3143 3144 3145 3146 3147 3148 3149 3150 3151
      bool interesting = false;
      for (struct ipa_agg_replacement_value *av = aggval; av; av = av->next)
	if (aggval->index == i)
	  {
	    interesting = true;
	    break;
	  }
      if (!interesting)
	continue;

      plats = ipa_get_parm_lattices (orig_caller_info, aggval->index);
      if (plats->aggs_bottom)
3152 3153
	return false;

3154 3155
      values = intersect_aggregates_with_edge (cs, i, values);
      if (!values.exists())
3156 3157
	return false;

3158 3159 3160 3161 3162 3163 3164 3165 3166 3167 3168 3169 3170 3171 3172 3173 3174
      for (struct ipa_agg_replacement_value *av = aggval; av; av = av->next)
	if (aggval->index == i)
	  {
	    struct ipa_agg_jf_item *item;
	    int j;
	    bool found = false;
	    FOR_EACH_VEC_ELT (values, j, item)
	      if (item->value
		  && item->offset == av->offset
		  && values_equal_for_ipcp_p (item->value, av->value))
		found = true;
	    if (!found)
	      {
		values.release();
		return false;
	      }
	  }
3175 3176 3177 3178
    }
  return true;
}

3179 3180 3181 3182 3183
/* Given an original NODE and a VAL for which we have already created a
   specialized clone, look whether there are incoming edges that still lead
   into the old node but now also bring the requested value and also conform to
   all other criteria such that they can be redirected the the special node.
   This function can therefore redirect the final edge in a SCC.  */
3184 3185

static void
3186
perhaps_add_new_callers (struct cgraph_node *node, struct ipcp_value *val)
3187
{
3188 3189
  struct ipcp_value_source *src;
  gcov_type redirected_sum = 0;
3190

3191
  for (src = val->sources; src; src = src->next)
3192
    {
3193 3194 3195 3196
      struct cgraph_edge *cs = src->cs;
      while (cs)
	{
	  enum availability availability;
3197 3198 3199
	  struct cgraph_node *dst = cgraph_function_node (cs->callee,
							  &availability);
	  if ((dst == node || IPA_NODE_REF (dst)->is_all_contexts_clone)
3200 3201 3202
	      && availability > AVAIL_OVERWRITABLE
	      && cgraph_edge_brings_value_p (cs, src))
	    {
3203 3204 3205
	      if (cgraph_edge_brings_all_scalars_for_node (cs, val->spec_node)
		  && cgraph_edge_brings_all_agg_vals_for_node (cs,
							       val->spec_node))
3206 3207 3208 3209
		{
		  if (dump_file)
		    fprintf (dump_file, " - adding an extra caller %s/%i"
			     " of %s/%i\n",
3210 3211 3212
			     xstrdup (cgraph_node_name (cs->caller)),
			     cs->caller->uid,
			     xstrdup (cgraph_node_name (val->spec_node)),
3213 3214 3215 3216 3217 3218 3219 3220
			     val->spec_node->uid);

		  cgraph_redirect_edge_callee (cs, val->spec_node);
		  redirected_sum += cs->count;
		}
	    }
	  cs = get_next_cgraph_edge_clone (cs);
	}
3221
    }
3222 3223 3224

  if (redirected_sum)
    update_specialized_profile (val->spec_node, node, redirected_sum);
3225 3226 3227
}


3228 3229
/* Copy KNOWN_BINFOS to KNOWN_VALS.  */

Razya Ladelsky committed
3230
static void
3231 3232
move_binfos_to_values (vec<tree> known_vals,
		       vec<tree> known_binfos)
Razya Ladelsky committed
3233
{
3234
  tree t;
3235
  int i;
Razya Ladelsky committed
3236

3237
  for (i = 0; known_binfos.iterate (i, &t); i++)
3238
    if (t)
3239
      known_vals[i] = t;
3240
}
3241

3242 3243 3244 3245 3246 3247 3248 3249 3250 3251 3252 3253 3254 3255 3256 3257 3258 3259 3260 3261 3262 3263 3264 3265 3266
/* Return true if there is a replacement equivalent to VALUE, INDEX and OFFSET
   among those in the AGGVALS list.  */

DEBUG_FUNCTION bool
ipcp_val_in_agg_replacements_p (struct ipa_agg_replacement_value *aggvals,
				int index, HOST_WIDE_INT offset, tree value)
{
  while (aggvals)
    {
      if (aggvals->index == index
	  && aggvals->offset == offset
	  && values_equal_for_ipcp_p (aggvals->value, value))
	return true;
      aggvals = aggvals->next;
    }
  return false;
}

/* Decide wheter to create a special version of NODE for value VAL of parameter
   at the given INDEX.  If OFFSET is -1, the value is for the parameter itself,
   otherwise it is stored at the given OFFSET of the parameter.  KNOWN_CSTS,
   KNOWN_BINFOS and KNOWN_AGGS describe the other already known values.  */

static bool
decide_about_value (struct cgraph_node *node, int index, HOST_WIDE_INT offset,
3267 3268
		    struct ipcp_value *val, vec<tree> known_csts,
		    vec<tree> known_binfos)
3269 3270 3271 3272
{
  struct ipa_agg_replacement_value *aggvals;
  int freq_sum, caller_count;
  gcov_type count_sum;
3273 3274
  vec<cgraph_edge_p> callers;
  vec<tree> kv;
3275 3276 3277 3278 3279 3280 3281 3282 3283 3284 3285 3286 3287 3288 3289 3290 3291 3292 3293 3294 3295 3296 3297 3298 3299 3300 3301 3302 3303 3304 3305 3306 3307 3308 3309 3310 3311 3312 3313 3314 3315 3316 3317 3318 3319 3320

  if (val->spec_node)
    {
      perhaps_add_new_callers (node, val);
      return false;
    }
  else if (val->local_size_cost + overall_size > max_new_size)
    {
      if (dump_file && (dump_flags & TDF_DETAILS))
	fprintf (dump_file, "   Ignoring candidate value because "
		 "max_new_size would be reached with %li.\n",
		 val->local_size_cost + overall_size);
      return false;
    }
  else if (!get_info_about_necessary_edges (val, &freq_sum, &count_sum,
					    &caller_count))
    return false;

  if (dump_file && (dump_flags & TDF_DETAILS))
    {
      fprintf (dump_file, " - considering value ");
      print_ipcp_constant_value (dump_file, val->value);
      fprintf (dump_file, " for parameter ");
      print_generic_expr (dump_file, ipa_get_param (IPA_NODE_REF (node),
						    index), 0);
      if (offset != -1)
	fprintf (dump_file, ", offset: " HOST_WIDE_INT_PRINT_DEC, offset);
      fprintf (dump_file, " (caller_count: %i)\n", caller_count);
    }

  if (!good_cloning_opportunity_p (node, val->local_time_benefit,
				   freq_sum, count_sum,
				   val->local_size_cost)
      && !good_cloning_opportunity_p (node,
				      val->local_time_benefit
				      + val->prop_time_benefit,
				      freq_sum, count_sum,
				      val->local_size_cost
				      + val->prop_size_cost))
    return false;

  if (dump_file)
    fprintf (dump_file, "  Creating a specialized node of %s/%i.\n",
	     cgraph_node_name (node), node->uid);

  callers = gather_edges_for_value (val, caller_count);
3321
  kv = known_csts.copy ();
3322 3323
  move_binfos_to_values (kv, known_binfos);
  if (offset == -1)
3324
    kv[index] = val->value;
3325 3326 3327 3328 3329 3330 3331 3332 3333 3334 3335 3336 3337
  find_more_scalar_values_for_callers_subset (node, kv, callers);
  aggvals = find_aggregate_values_for_callers_subset (node, callers);
  gcc_checking_assert (offset == -1
		       || ipcp_val_in_agg_replacements_p (aggvals, index,
							  offset, val->value));
  val->spec_node = create_specialized_node (node, kv, aggvals, callers);
  overall_size += val->local_size_cost;

  /* TODO: If for some lattice there is only one other known value
     left, make a special node for it too. */

  return true;
}
3338

3339
/* Decide whether and what specialized clones of NODE should be created.  */
3340

3341 3342 3343 3344 3345
static bool
decide_whether_version_node (struct cgraph_node *node)
{
  struct ipa_node_params *info = IPA_NODE_REF (node);
  int i, count = ipa_get_param_count (info);
3346
  vec<tree> known_csts, known_binfos;
3347
  vec<ipa_agg_jump_function_t> known_aggs = vNULL;
3348
  bool ret = false;
3349

3350 3351
  if (count == 0)
    return false;
3352

3353 3354 3355
  if (dump_file && (dump_flags & TDF_DETAILS))
    fprintf (dump_file, "\nEvaluating opportunities for %s/%i.\n",
	     cgraph_node_name (node), node->uid);
3356

3357
  gather_context_independent_values (info, &known_csts, &known_binfos,
3358 3359
				  info->do_clone_for_all_contexts ? &known_aggs
				  : NULL, NULL);
3360

3361
  for (i = 0; i < count ;i++)
3362
    {
3363 3364
      struct ipcp_param_lattices *plats = ipa_get_parm_lattices (info, i);
      struct ipcp_lattice *lat = &plats->itself;
3365
      struct ipcp_value *val;
3366

3367
      if (!lat->bottom
3368 3369
	  && !known_csts[i]
	  && !known_binfos[i])
3370 3371 3372
	for (val = lat->values; val; val = val->next)
	  ret |= decide_about_value (node, i, -1, val, known_csts,
				     known_binfos);
3373

3374
      if (!plats->aggs_bottom)
Razya Ladelsky committed
3375
	{
3376 3377 3378 3379 3380 3381 3382 3383 3384 3385 3386
	  struct ipcp_agg_lattice *aglat;
	  struct ipcp_value *val;
	  for (aglat = plats->aggs; aglat; aglat = aglat->next)
	    if (!aglat->bottom && aglat->values
		/* If the following is false, the one value is in
		   known_aggs.  */
		&& (plats->aggs_contain_variable
		    || !ipa_lat_is_single_const (aglat)))
	      for (val = aglat->values; val; val = val->next)
		ret |= decide_about_value (node, i, aglat->offset, val,
					   known_csts, known_binfos);
3387
	}
3388
        info = IPA_NODE_REF (node);
3389
    }
3390

3391
  if (info->do_clone_for_all_contexts)
3392
    {
3393
      struct cgraph_node *clone;
3394
      vec<cgraph_edge_p> callers;
3395

3396 3397 3398 3399
      if (dump_file)
	fprintf (dump_file, " - Creating a specialized node of %s/%i "
		 "for all known contexts.\n", cgraph_node_name (node),
		 node->uid);
3400

3401 3402
      callers = collect_callers_of_node (node);
      move_binfos_to_values (known_csts, known_binfos);
3403
      clone = create_specialized_node (node, known_csts,
3404 3405
			       known_aggs_to_agg_replacement_list (known_aggs),
			       callers);
3406
      info = IPA_NODE_REF (node);
3407 3408
      info->do_clone_for_all_contexts = false;
      IPA_NODE_REF (clone)->is_all_contexts_clone = true;
3409 3410 3411
      for (i = 0; i < count ; i++)
	vec_free (known_aggs[i].items);
      known_aggs.release ();
3412 3413 3414
      ret = true;
    }
  else
3415
    known_csts.release ();
3416

3417
  known_binfos.release ();
3418 3419
  return ret;
}
3420

3421
/* Transitively mark all callees of NODE within the same SCC as not dead.  */
3422

3423 3424 3425 3426
static void
spread_undeadness (struct cgraph_node *node)
{
  struct cgraph_edge *cs;
3427

3428 3429 3430 3431 3432
  for (cs = node->callees; cs; cs = cs->next_callee)
    if (edge_within_scc (cs))
      {
	struct cgraph_node *callee;
	struct ipa_node_params *info;
3433

3434 3435
	callee = cgraph_function_node (cs->callee, NULL);
	info = IPA_NODE_REF (callee);
3436

3437 3438 3439 3440 3441 3442 3443 3444 3445 3446 3447 3448 3449 3450 3451 3452 3453 3454 3455 3456 3457 3458 3459 3460 3461 3462 3463 3464 3465 3466 3467 3468 3469 3470 3471 3472 3473
	if (info->node_dead)
	  {
	    info->node_dead = 0;
	    spread_undeadness (callee);
	  }
      }
}

/* Return true if NODE has a caller from outside of its SCC that is not
   dead.  Worker callback for cgraph_for_node_and_aliases.  */

static bool
has_undead_caller_from_outside_scc_p (struct cgraph_node *node,
				     void *data ATTRIBUTE_UNUSED)
{
  struct cgraph_edge *cs;

  for (cs = node->callers; cs; cs = cs->next_caller)
    if (cs->caller->thunk.thunk_p
	&& cgraph_for_node_and_aliases (cs->caller,
					has_undead_caller_from_outside_scc_p,
					NULL, true))
      return true;
    else if (!edge_within_scc (cs)
	     && !IPA_NODE_REF (cs->caller)->node_dead)
      return true;
  return false;
}


/* Identify nodes within the same SCC as NODE which are no longer needed
   because of new clones and will be removed as unreachable.  */

static void
identify_dead_nodes (struct cgraph_node *node)
{
  struct cgraph_node *v;
3474
  for (v = node; v ; v = ((struct ipa_dfs_info *) v->symbol.aux)->next_cycle)
3475 3476 3477 3478 3479 3480
    if (cgraph_will_be_removed_from_program_if_no_direct_calls (v)
	&& !cgraph_for_node_and_aliases (v,
					 has_undead_caller_from_outside_scc_p,
					 NULL, true))
      IPA_NODE_REF (v)->node_dead = 1;

3481
  for (v = node; v ; v = ((struct ipa_dfs_info *) v->symbol.aux)->next_cycle)
3482 3483 3484 3485 3486
    if (!IPA_NODE_REF (v)->node_dead)
      spread_undeadness (v);

  if (dump_file && (dump_flags & TDF_DETAILS))
    {
3487
      for (v = node; v ; v = ((struct ipa_dfs_info *) v->symbol.aux)->next_cycle)
3488 3489 3490
	if (IPA_NODE_REF (v)->node_dead)
	  fprintf (dump_file, "  Marking node as dead: %s/%i.\n",
		   cgraph_node_name (v), v->uid);
3491
    }
3492 3493 3494 3495 3496 3497 3498 3499 3500 3501 3502 3503
}

/* The decision stage.  Iterate over the topological order of call graph nodes
   TOPO and make specialized clones if deemed beneficial.  */

static void
ipcp_decision_stage (struct topo_info *topo)
{
  int i;

  if (dump_file)
    fprintf (dump_file, "\nIPA decision stage:\n\n");
3504

3505
  for (i = topo->nnodes - 1; i >= 0; i--)
3506
    {
3507 3508 3509 3510 3511 3512 3513
      struct cgraph_node *node = topo->order[i];
      bool change = false, iterate = true;

      while (iterate)
	{
	  struct cgraph_node *v;
	  iterate = false;
3514
	  for (v = node; v ; v = ((struct ipa_dfs_info *) v->symbol.aux)->next_cycle)
3515 3516 3517 3518 3519 3520 3521 3522
	    if (cgraph_function_with_gimple_body_p (v)
		&& ipcp_versionable_function_p (v))
	      iterate |= decide_whether_version_node (v);

	  change |= iterate;
	}
      if (change)
	identify_dead_nodes (node);
Razya Ladelsky committed
3523 3524 3525 3526
    }
}

/* The IPCP driver.  */
3527

3528
static unsigned int
Razya Ladelsky committed
3529 3530
ipcp_driver (void)
{
3531 3532 3533 3534 3535 3536 3537 3538 3539 3540 3541 3542
  struct cgraph_2edge_hook_list *edge_duplication_hook_holder;
  struct topo_info topo;

  ipa_check_create_node_params ();
  ipa_check_create_edge_args ();
  grow_next_edge_clone_vector ();
  edge_duplication_hook_holder =
    cgraph_add_edge_duplication_hook (&ipcp_edge_duplication_hook, NULL);
  ipcp_values_pool = create_alloc_pool ("IPA-CP values",
					sizeof (struct ipcp_value), 32);
  ipcp_sources_pool = create_alloc_pool ("IPA-CP value sources",
					 sizeof (struct ipcp_value_source), 64);
3543 3544 3545
  ipcp_agg_lattice_pool = create_alloc_pool ("IPA_CP aggregate lattices",
					     sizeof (struct ipcp_agg_lattice),
					     32);
Razya Ladelsky committed
3546 3547
  if (dump_file)
    {
3548 3549 3550 3551
      fprintf (dump_file, "\nIPA structures before propagation:\n");
      if (dump_flags & TDF_DETAILS)
        ipa_print_all_params (dump_file);
      ipa_print_all_jump_functions (dump_file);
Razya Ladelsky committed
3552
    }
3553 3554 3555 3556 3557 3558 3559 3560

  /* Topological sort.  */
  build_toporder_info (&topo);
  /* Do the interprocedural propagation.  */
  ipcp_propagate_stage (&topo);
  /* Decide what constant propagation and cloning should be performed.  */
  ipcp_decision_stage (&topo);

Razya Ladelsky committed
3561
  /* Free all IPCP structures.  */
3562
  free_toporder_info (&topo);
3563
  next_edge_clone.release ();
3564
  cgraph_remove_edge_duplication_hook (edge_duplication_hook_holder);
3565
  ipa_free_all_structures_after_ipa_cp ();
Razya Ladelsky committed
3566 3567
  if (dump_file)
    fprintf (dump_file, "\nIPA constant propagation end\n");
3568
  return 0;
Razya Ladelsky committed
3569 3570
}

3571 3572 3573 3574
/* Initialization and computation of IPCP data structures.  This is the initial
   intraprocedural analysis of functions, which gathers information to be
   propagated later on.  */

3575 3576 3577
static void
ipcp_generate_summary (void)
{
3578 3579
  struct cgraph_node *node;

3580 3581 3582
  if (dump_file)
    fprintf (dump_file, "\nIPA constant propagation start:\n");
  ipa_register_cgraph_hooks ();
3583

3584
  FOR_EACH_FUNCTION_WITH_GIMPLE_BODY (node)
3585
      {
3586 3587
	node->local.versionable
	  = tree_versionable_function_p (node->symbol.decl);
3588 3589
	ipa_analyze_node (node);
      }
3590 3591
}

3592
/* Write ipcp summary for nodes in SET.  */
3593

3594
static void
3595
ipcp_write_summary (void)
3596
{
3597
  ipa_prop_write_jump_functions ();
3598 3599 3600
}

/* Read ipcp summary.  */
3601

3602 3603 3604 3605 3606 3607
static void
ipcp_read_summary (void)
{
  ipa_prop_read_jump_functions ();
}

Razya Ladelsky committed
3608
/* Gate for IPCP optimization.  */
3609

Razya Ladelsky committed
3610 3611 3612
static bool
cgraph_gate_cp (void)
{
3613
  /* FIXME: We should remove the optimize check after we ensure we never run
3614
     IPA passes when not optimizing.  */
3615
  return flag_ipa_cp && optimize;
Razya Ladelsky committed
3616 3617
}

3618
struct ipa_opt_pass_d pass_ipa_cp =
3619 3620
{
 {
3621
  IPA_PASS,
Razya Ladelsky committed
3622
  "cp",				/* name */
3623
  OPTGROUP_NONE,                /* optinfo_flags */
Razya Ladelsky committed
3624 3625 3626 3627 3628 3629 3630
  cgraph_gate_cp,		/* gate */
  ipcp_driver,			/* execute */
  NULL,				/* sub */
  NULL,				/* next */
  0,				/* static_pass_number */
  TV_IPA_CONSTANT_PROP,		/* tv_id */
  0,				/* properties_required */
3631
  0,				/* properties_provided */
Razya Ladelsky committed
3632 3633
  0,				/* properties_destroyed */
  0,				/* todo_flags_start */
3634
  TODO_dump_symtab |
3635
  TODO_remove_functions | TODO_ggc_collect /* todo_flags_finish */
3636 3637
 },
 ipcp_generate_summary,			/* generate_summary */
3638 3639
 ipcp_write_summary,			/* write_summary */
 ipcp_read_summary,			/* read_summary */
3640 3641
 ipa_prop_write_all_agg_replacement,	/* write_optimization_summary */
 ipa_prop_read_all_agg_replacement,	/* read_optimization_summary */
3642
 NULL,			 		/* stmt_fixup */
3643
 0,					/* TODOs */
3644
 ipcp_transform_function,		/* function_transform */
3645
 NULL,					/* variable_transform */
Razya Ladelsky committed
3646
};