hash-table.h: support non-zero empty values in empty_slow (v2)
[gcc.git] / gcc / ipa-prop.c
index 642111def51e4e4098fed77a79c17116b105319b..12cdb95cf2ab7bea181b774af6b2213ec1c76bc8 100644 (file)
@@ -1,5 +1,5 @@
 /* Interprocedural analyses.
-   Copyright (C) 2005-2016 Free Software Foundation, Inc.
+   Copyright (C) 2005-2020 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -45,24 +45,112 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-cfg.h"
 #include "tree-dfa.h"
 #include "tree-inline.h"
-#include "ipa-inline.h"
+#include "ipa-fnsummary.h"
 #include "gimple-pretty-print.h"
-#include "params.h"
 #include "ipa-utils.h"
 #include "dbgcnt.h"
 #include "domwalk.h"
 #include "builtins.h"
+#include "tree-cfgcleanup.h"
 
 /* Function summary where the parameter infos are actually stored. */
 ipa_node_params_t *ipa_node_params_sum = NULL;
-/* Vector of IPA-CP transformation data for each clone.  */
-vec<ipcp_transformation_summary, va_gc> *ipcp_transformations;
-/* Vector where the parameter infos are actually stored. */
-vec<ipa_edge_args, va_gc> *ipa_edge_args_vector;
+
+function_summary <ipcp_transformation *> *ipcp_transformation_sum = NULL;
+
+/* Edge summary for IPA-CP edge information.  */
+ipa_edge_args_sum_t *ipa_edge_args_sum;
+
+/* Traits for a hash table for reusing already existing ipa_bits. */
+
+struct ipa_bit_ggc_hash_traits : public ggc_cache_remove <ipa_bits *>
+{
+  typedef ipa_bits *value_type;
+  typedef ipa_bits *compare_type;
+  static hashval_t
+  hash (const ipa_bits *p)
+  {
+    hashval_t t = (hashval_t) p->value.to_shwi ();
+    return iterative_hash_host_wide_int (p->mask.to_shwi (), t);
+  }
+  static bool
+  equal (const ipa_bits *a, const ipa_bits *b)
+    {
+      return a->value == b->value && a->mask == b->mask;
+    }
+  static const bool empty_zero_p = true;
+  static void
+  mark_empty (ipa_bits *&p)
+    {
+      p = NULL;
+    }
+  static bool
+  is_empty (const ipa_bits *p)
+    {
+      return p == NULL;
+    }
+  static bool
+  is_deleted (const ipa_bits *p)
+    {
+      return p == reinterpret_cast<const ipa_bits *> (1);
+    }
+  static void
+  mark_deleted (ipa_bits *&p)
+    {
+      p = reinterpret_cast<ipa_bits *> (1);
+    }
+};
+
+/* Hash table for avoid repeated allocations of equal ipa_bits.  */
+static GTY ((cache)) hash_table<ipa_bit_ggc_hash_traits> *ipa_bits_hash_table;
+
+/* Traits for a hash table for reusing value_ranges used for IPA.  Note that
+   the equiv bitmap is not hashed and is expected to be NULL.  */
+
+struct ipa_vr_ggc_hash_traits : public ggc_cache_remove <value_range *>
+{
+  typedef value_range *value_type;
+  typedef value_range *compare_type;
+  static hashval_t
+  hash (const value_range *p)
+    {
+      inchash::hash hstate (p->kind ());
+      inchash::add_expr (p->min (), hstate);
+      inchash::add_expr (p->max (), hstate);
+      return hstate.end ();
+    }
+  static bool
+  equal (const value_range *a, const value_range *b)
+    {
+      return a->equal_p (*b);
+    }
+  static const bool empty_zero_p = true;
+  static void
+  mark_empty (value_range *&p)
+    {
+      p = NULL;
+    }
+  static bool
+  is_empty (const value_range *p)
+    {
+      return p == NULL;
+    }
+  static bool
+  is_deleted (const value_range *p)
+    {
+      return p == reinterpret_cast<const value_range *> (1);
+    }
+  static void
+  mark_deleted (value_range *&p)
+    {
+      p = reinterpret_cast<value_range *> (1);
+    }
+};
+
+/* Hash table for avoid repeated allocations of equal value_ranges.  */
+static GTY ((cache)) hash_table<ipa_vr_ggc_hash_traits> *ipa_vr_hash_table;
 
 /* Holders of ipa cgraph hooks: */
-static struct cgraph_edge_hook_list *edge_removal_hook_holder;
-static struct cgraph_2edge_hook_list *edge_duplication_hook_holder;
 static struct cgraph_node_hook_list *function_insertion_hook_holder;
 
 /* Description of a reference to an IPA constant.  */
@@ -99,13 +187,14 @@ ipa_func_spec_opts_forbid_analysis_p (struct cgraph_node *node)
    to INFO.  */
 
 static int
-ipa_get_param_decl_index_1 (vec<ipa_param_descriptor> descriptors, tree ptree)
+ipa_get_param_decl_index_1 (vec<ipa_param_descriptor, va_gc> *descriptors,
+                           tree ptree)
 {
   int i, count;
 
-  count = descriptors.length ();
+  count = vec_safe_length (descriptors);
   for (i = 0; i < count; i++)
-    if (descriptors[i].decl_or_type == ptree)
+    if ((*descriptors)[i].decl_or_type == ptree)
       return i;
 
   return -1;
@@ -115,7 +204,7 @@ ipa_get_param_decl_index_1 (vec<ipa_param_descriptor> descriptors, tree ptree)
    to INFO.  */
 
 int
-ipa_get_param_decl_index (struct ipa_node_params *info, tree ptree)
+ipa_get_param_decl_index (class ipa_node_params *info, tree ptree)
 {
   return ipa_get_param_decl_index_1 (info->descriptors, ptree);
 }
@@ -125,7 +214,7 @@ ipa_get_param_decl_index (struct ipa_node_params *info, tree ptree)
 
 static void
 ipa_populate_param_decls (struct cgraph_node *node,
-                         vec<ipa_param_descriptor> &descriptors)
+                         vec<ipa_param_descriptor, va_gc> &descriptors)
 {
   tree fndecl;
   tree fnargs;
@@ -139,8 +228,10 @@ ipa_populate_param_decls (struct cgraph_node *node,
   for (parm = fnargs; parm; parm = DECL_CHAIN (parm))
     {
       descriptors[param_num].decl_or_type = parm;
-      descriptors[param_num].move_cost = estimate_move_cost (TREE_TYPE (parm),
-                                                            true);
+      unsigned int cost = estimate_move_cost (TREE_TYPE (parm), true);
+      descriptors[param_num].move_cost = cost;
+      /* Watch overflow, move_cost is a bitfield.  */
+      gcc_checking_assert (cost == descriptors[param_num].move_cost);
       param_num++;
     }
 }
@@ -165,26 +256,31 @@ count_formal_params (tree fndecl)
    using ipa_initialize_node_params. */
 
 void
-ipa_dump_param (FILE *file, struct ipa_node_params *info, int i)
+ipa_dump_param (FILE *file, class ipa_node_params *info, int i)
 {
   fprintf (file, "param #%i", i);
-  if (info->descriptors[i].decl_or_type)
+  if ((*info->descriptors)[i].decl_or_type)
     {
       fprintf (file, " ");
-      print_generic_expr (file, info->descriptors[i].decl_or_type, 0);
+      print_generic_expr (file, (*info->descriptors)[i].decl_or_type);
     }
 }
 
-/* Initialize the ipa_node_params structure associated with NODE 
-   to hold PARAM_COUNT parameters.  */
+/* If necessary, allocate vector of parameter descriptors in info of NODE.
+   Return true if they were allocated, false if not.  */
 
-void
+static bool
 ipa_alloc_node_params (struct cgraph_node *node, int param_count)
 {
-  struct ipa_node_params *info = IPA_NODE_REF (node);
+  class ipa_node_params *info = IPA_NODE_REF_GET_CREATE (node);
 
-  if (!info->descriptors.exists () && param_count)
-    info->descriptors.safe_grow_cleared (param_count);
+  if (!info->descriptors && param_count)
+    {
+      vec_safe_grow_cleared (info->descriptors, param_count);
+      return true;
+    }
+  else
+    return false;
 }
 
 /* Initialize the ipa_node_params structure associated with NODE by counting
@@ -194,13 +290,11 @@ ipa_alloc_node_params (struct cgraph_node *node, int param_count)
 void
 ipa_initialize_node_params (struct cgraph_node *node)
 {
-  struct ipa_node_params *info = IPA_NODE_REF (node);
+  class ipa_node_params *info = IPA_NODE_REF_GET_CREATE (node);
 
-  if (!info->descriptors.exists ())
-    {
-      ipa_alloc_node_params (node, count_formal_params (node->decl));
-      ipa_populate_param_decls (node, info->descriptors);
-    }
+  if (!info->descriptors
+      && ipa_alloc_node_params (node, count_formal_params (node->decl)))
+    ipa_populate_param_decls (node, *info->descriptors);
 }
 
 /* Print the jump functions associated with call graph edge CS to file F.  */
@@ -226,13 +320,12 @@ ipa_print_node_jump_functions_for_edge (FILE *f, struct cgraph_edge *cs)
        {
          tree val = jump_func->value.constant.value;
          fprintf (f, "CONST: ");
-         print_generic_expr (f, val, 0);
+         print_generic_expr (f, val);
          if (TREE_CODE (val) == ADDR_EXPR
              && TREE_CODE (TREE_OPERAND (val, 0)) == CONST_DECL)
            {
              fprintf (f, " -> ");
-             print_generic_expr (f, DECL_INITIAL (TREE_OPERAND (val, 0)),
-                                 0);
+             print_generic_expr (f, DECL_INITIAL (TREE_OPERAND (val, 0)));
            }
          fprintf (f, "\n");
        }
@@ -245,8 +338,7 @@ ipa_print_node_jump_functions_for_edge (FILE *f, struct cgraph_edge *cs)
          if (jump_func->value.pass_through.operation != NOP_EXPR)
            {
              fprintf (f, " ");
-             print_generic_expr (f,
-                                 jump_func->value.pass_through.operand, 0);
+             print_generic_expr (f, jump_func->value.pass_through.operand);
            }
          if (jump_func->value.pass_through.agg_preserved)
            fprintf (f, ", agg_preserved");
@@ -270,23 +362,50 @@ ipa_print_node_jump_functions_for_edge (FILE *f, struct cgraph_edge *cs)
 
          fprintf (f, "         Aggregate passed by %s:\n",
                   jump_func->agg.by_ref ? "reference" : "value");
-         FOR_EACH_VEC_SAFE_ELT (jump_func->agg.items, j, item)
+         FOR_EACH_VEC_ELT (*jump_func->agg.items, j, item)
            {
              fprintf (f, "           offset: " HOST_WIDE_INT_PRINT_DEC ", ",
                       item->offset);
-             if (TYPE_P (item->value))
-               fprintf (f, "clobber of " HOST_WIDE_INT_PRINT_DEC " bits",
-                        tree_to_uhwi (TYPE_SIZE (item->value)));
-             else
+             fprintf (f, "type: ");
+             print_generic_expr (f, item->type);
+             fprintf (f, ", ");
+             if (item->jftype == IPA_JF_PASS_THROUGH)
+               fprintf (f, "PASS THROUGH: %d,",
+                        item->value.pass_through.formal_id);
+             else if (item->jftype == IPA_JF_LOAD_AGG)
+               {
+                 fprintf (f, "LOAD AGG: %d",
+                          item->value.pass_through.formal_id);
+                 fprintf (f, " [offset: " HOST_WIDE_INT_PRINT_DEC ", by %s],",
+                          item->value.load_agg.offset,
+                          item->value.load_agg.by_ref ? "reference"
+                                                      : "value");
+               }
+
+             if (item->jftype == IPA_JF_PASS_THROUGH
+                 || item->jftype == IPA_JF_LOAD_AGG)
+               {
+                 fprintf (f, " op %s",
+                    get_tree_code_name (item->value.pass_through.operation));
+                 if (item->value.pass_through.operation != NOP_EXPR)
+                   {
+                     fprintf (f, " ");
+                     print_generic_expr (f, item->value.pass_through.operand);
+                   }
+               }
+             else if (item->jftype == IPA_JF_CONST)
                {
-                 fprintf (f, "cst: ");
-                 print_generic_expr (f, item->value, 0);
+                 fprintf (f, "CONST: ");
+                 print_generic_expr (f, item->value.constant);
                }
+             else if (item->jftype == IPA_JF_UNKNOWN)
+               fprintf (f, "UNKNOWN: " HOST_WIDE_INT_PRINT_DEC " bits",
+                        tree_to_uhwi (TYPE_SIZE (item->type)));
              fprintf (f, "\n");
            }
        }
 
-      struct ipa_polymorphic_call_context *ctx
+      class ipa_polymorphic_call_context *ctx
        = ipa_get_ith_polymorhic_call_context (IPA_EDGE_REF (cs), i);
       if (ctx && !ctx->useless_p ())
        {
@@ -294,23 +413,25 @@ ipa_print_node_jump_functions_for_edge (FILE *f, struct cgraph_edge *cs)
          ctx->dump (dump_file);
        }
 
-      if (jump_func->bits.known)
+      if (jump_func->bits)
        {
-         fprintf (f, "         value: "); print_hex (jump_func->bits.value, f);
-         fprintf (f, ", mask: "); print_hex (jump_func->bits.mask, f);
+         fprintf (f, "         value: ");
+         print_hex (jump_func->bits->value, f);
+         fprintf (f, ", mask: ");
+         print_hex (jump_func->bits->mask, f);
          fprintf (f, "\n");
        }
       else
        fprintf (f, "         Unknown bits\n");
 
-      if (jump_func->vr_known)
+      if (jump_func->m_vr)
        {
          fprintf (f, "         VR  ");
          fprintf (f, "%s[",
-                  (jump_func->m_vr.type == VR_ANTI_RANGE) ? "~" : "");
-         print_decs (jump_func->m_vr.min, f);
+                  (jump_func->m_vr->kind () == VR_ANTI_RANGE) ? "~" : "");
+         print_decs (wi::to_wide (jump_func->m_vr->min ()), f);
          fprintf (f, ", ");
-         print_decs (jump_func->m_vr.max, f);
+         print_decs (wi::to_wide (jump_func->m_vr->max ()), f);
          fprintf (f, "]\n");
        }
       else
@@ -327,25 +448,22 @@ ipa_print_node_jump_functions (FILE *f, struct cgraph_node *node)
 {
   struct cgraph_edge *cs;
 
-  fprintf (f, "  Jump functions of caller  %s/%i:\n", node->name (),
-          node->order);
+  fprintf (f, "  Jump functions of caller  %s:\n", node->dump_name ());
   for (cs = node->callees; cs; cs = cs->next_callee)
     {
-      if (!ipa_edge_args_info_available_for_edge_p (cs))
-       continue;
 
-      fprintf (f, "    callsite  %s/%i -> %s/%i : \n",
-              xstrdup_for_dump (node->name ()), node->order,
-              xstrdup_for_dump (cs->callee->name ()),
-              cs->callee->order);
-      ipa_print_node_jump_functions_for_edge (f, cs);
+      fprintf (f, "    callsite  %s -> %s : \n",
+              node->dump_name (),
+              cs->callee->dump_name ());
+      if (!ipa_edge_args_info_available_for_edge_p (cs))
+       fprintf (f, "       no arg info\n");
+      else
+        ipa_print_node_jump_functions_for_edge (f, cs);
     }
 
   for (cs = node->indirect_calls; cs; cs = cs->next_callee)
     {
-      struct cgraph_indirect_call_info *ii;
-      if (!ipa_edge_args_info_available_for_edge_p (cs))
-       continue;
+      class cgraph_indirect_call_info *ii;
 
       ii = cs->indirect_info;
       if (ii->agg_contents)
@@ -369,7 +487,10 @@ ipa_print_node_jump_functions (FILE *f, struct cgraph_node *node)
        fprintf (f, "\n");
       if (ii->polymorphic)
        ii->context.dump (f);
-      ipa_print_node_jump_functions_for_edge (f, cs);
+      if (!ipa_edge_args_info_available_for_edge_p (cs))
+       fprintf (f, "       no arg info\n");
+      else
+        ipa_print_node_jump_functions_for_edge (f, cs);
     }
 }
 
@@ -393,8 +514,6 @@ static void
 ipa_set_jf_unknown (struct ipa_jump_func *jfunc)
 {
   jfunc->type = IPA_JF_UNKNOWN;
-  jfunc->bits.known = false;
-  jfunc->vr_known = false;
 }
 
 /* Set JFUNC to be a copy of another jmp (to be used by jump function
@@ -565,7 +684,7 @@ stmt_may_be_vtbl_ptr_store (gimple *stmt)
          if (TREE_CODE (lhs) == COMPONENT_REF
              && !DECL_VIRTUAL_P (TREE_OPERAND (lhs, 1)))
            return false;
-         /* In the future we might want to use get_base_ref_and_offset to find
+         /* In the future we might want to use get_ref_base_and_extent to find
             if there is a field corresponding to the offset and if so, proceed
             almost like if it was a component ref.  */
        }
@@ -598,14 +717,14 @@ check_stmt_for_type_change (ao_ref *ao ATTRIBUTE_UNUSED, tree vdef, void *data)
    in between beggining of the function until CALL is invoked.
 
    Generally functions are not allowed to change type of such instances,
-   but they call destructors.  We assume that methods can not destroy the THIS
+   but they call destructors.  We assume that methods cannot destroy the THIS
    pointer.  Also as a special cases, constructor and destructors may change
    type of the THIS pointer.  */
 
 static bool
 param_type_may_change_p (tree function, tree arg, gimple *call)
 {
-  /* Pure functions can not do any changes on the dynamic type;
+  /* Pure functions cannot do any changes on the dynamic type;
      that require writting to memory.  */
   if (flags_from_decl_or_type (function) & (ECF_PURE | ECF_CONST))
     return false;
@@ -649,8 +768,7 @@ param_type_may_change_p (tree function, tree arg, gimple *call)
 
 /* Detect whether the dynamic type of ARG of COMP_TYPE has changed (before
    callsite CALL) by looking for assignments to its virtual table pointer.  If
-   it is, return true and fill in the jump function JFUNC with relevant type
-   information or set it to unknown.  ARG is the object itself (not a pointer
+   it is, return true.  ARG is the object itself (not a pointer
    to it, unless dereferenced).  BASE is the base of the memory access as
    returned by get_ref_base_and_extent, as is the offset. 
 
@@ -658,13 +776,12 @@ param_type_may_change_p (tree function, tree arg, gimple *call)
    that does the heavy work which is usually unnecesary.  */
 
 static bool
-detect_type_change_from_memory_writes (tree arg, tree base, tree comp_type,
-                                      gcall *call, struct ipa_jump_func *jfunc,
+detect_type_change_from_memory_writes (ipa_func_body_info *fbi, tree arg,
+                                      tree base, tree comp_type, gcall *call,
                                       HOST_WIDE_INT offset)
 {
   struct prop_type_change_info tci;
   ao_ref ao;
-  bool entry_reached = false;
 
   gcc_checking_assert (DECL_P (arg)
                       || TREE_CODE (arg) == MEM_REF
@@ -692,24 +809,25 @@ detect_type_change_from_memory_writes (tree arg, tree base, tree comp_type,
   tci.object = get_base_address (arg);
   tci.type_maybe_changed = false;
 
-  walk_aliased_vdefs (&ao, gimple_vuse (call), check_stmt_for_type_change,
-                     &tci, NULL, &entry_reached);
-  if (!tci.type_maybe_changed)
+  int walked
+    = walk_aliased_vdefs (&ao, gimple_vuse (call), check_stmt_for_type_change,
+                         &tci, NULL, NULL, fbi->aa_walk_budget + 1);
+
+  if (walked >= 0 && !tci.type_maybe_changed)
     return false;
 
-  ipa_set_jf_unknown (jfunc);
   return true;
 }
 
 /* Detect whether the dynamic type of ARG of COMP_TYPE may have changed.
-   If it is, return true and fill in the jump function JFUNC with relevant type
-   information or set it to unknown.  ARG is the object itself (not a pointer
+   If it is, return true.  ARG is the object itself (not a pointer
    to it, unless dereferenced).  BASE is the base of the memory access as
    returned by get_ref_base_and_extent, as is the offset.  */
 
 static bool
-detect_type_change (tree arg, tree base, tree comp_type, gcall *call,
-                   struct ipa_jump_func *jfunc, HOST_WIDE_INT offset)
+detect_type_change (ipa_func_body_info *fbi, tree arg, tree base,
+                   tree comp_type, gcall *call,
+                   HOST_WIDE_INT offset)
 {
   if (!flag_devirtualize)
     return false;
@@ -719,8 +837,8 @@ detect_type_change (tree arg, tree base, tree comp_type, gcall *call,
                                   TREE_OPERAND (base, 0),
                                   call))
     return false;
-  return detect_type_change_from_memory_writes (arg, base, comp_type,
-                                               call, jfunc, offset);
+  return detect_type_change_from_memory_writes (fbi, arg, base, comp_type,
+                                               call, offset);
 }
 
 /* Like detect_type_change but ARG is supposed to be a non-dereferenced pointer
@@ -728,8 +846,8 @@ detect_type_change (tree arg, tree base, tree comp_type, gcall *call,
    be zero).  */
 
 static bool
-detect_type_change_ssa (tree arg, tree comp_type,
-                       gcall *call, struct ipa_jump_func *jfunc)
+detect_type_change_ssa (ipa_func_body_info *fbi, tree arg, tree comp_type,
+                       gcall *call)
 {
   gcc_checking_assert (TREE_CODE (arg) == SSA_NAME);
   if (!flag_devirtualize
@@ -742,8 +860,8 @@ detect_type_change_ssa (tree arg, tree comp_type,
   arg = build2 (MEM_REF, ptr_type_node, arg,
                build_int_cst (ptr_type_node, 0));
 
-  return detect_type_change_from_memory_writes (arg, arg, comp_type,
-                                               call, jfunc, 0);
+  return detect_type_change_from_memory_writes (fbi, arg, arg, comp_type,
+                                               call, 0);
 }
 
 /* Callback of walk_aliased_vdefs.  Flags that it has been invoked to the
@@ -758,16 +876,6 @@ mark_modified (ao_ref *ao ATTRIBUTE_UNUSED, tree vdef ATTRIBUTE_UNUSED,
   return true;
 }
 
-/* Return true if we have already walked so many statements in AA that we
-   should really just start giving up.  */
-
-static bool
-aa_overwalked (struct ipa_func_body_info *fbi)
-{
-  gcc_checking_assert (fbi);
-  return fbi->aa_walked > (unsigned) PARAM_VALUE (PARAM_IPA_MAX_AA_STEPS);
-}
-
 /* Find the nearest valid aa status for parameter specified by INDEX that
    dominates BB.  */
 
@@ -834,46 +942,44 @@ parm_preserved_before_stmt_p (struct ipa_func_body_info *fbi, int index,
   if (TREE_READONLY (base))
     return true;
 
-  /* FIXME: FBI can be NULL if we are being called from outside
-     ipa_node_analysis or ipcp_transform_function, which currently happens
-     during inlining analysis.  It would be great to extend fbi's lifetime and
-     always have it.  Currently, we are just not afraid of too much walking in
-     that case.  */
-  if (fbi)
-    {
-      if (aa_overwalked (fbi))
-       return false;
-      paa = parm_bb_aa_status_for_bb (fbi, gimple_bb (stmt), index);
-      if (paa->parm_modified)
-       return false;
-    }
-  else
-    paa = NULL;
+  gcc_checking_assert (fbi);
+  paa = parm_bb_aa_status_for_bb (fbi, gimple_bb (stmt), index);
+  if (paa->parm_modified)
+    return false;
 
   gcc_checking_assert (gimple_vuse (stmt) != NULL_TREE);
   ao_ref_init (&refd, parm_load);
   int walked = walk_aliased_vdefs (&refd, gimple_vuse (stmt), mark_modified,
-                                  &modified, NULL);
-  if (fbi)
-    fbi->aa_walked += walked;
+                                  &modified, NULL, NULL,
+                                  fbi->aa_walk_budget + 1);
+  if (walked < 0)
+    {
+      modified = true;
+      if (fbi)
+       fbi->aa_walk_budget = 0;
+    }
+  else if (fbi)
+    fbi->aa_walk_budget -= walked;
   if (paa && modified)
     paa->parm_modified = true;
   return !modified;
 }
 
-/* Main worker for load_from_unmodified_param and load_from_param.
-   If STMT is an assignment that loads a value from an parameter declaration,
-   return the index of the parameter in ipa_node_params.  Otherwise return -1.  */
+/* If STMT is an assignment that loads a value from an parameter declaration,
+   return the index of the parameter in ipa_node_params which has not been
+   modified.  Otherwise return -1.  */
 
 static int
-load_from_param_1 (struct ipa_func_body_info *fbi,
-                  vec<ipa_param_descriptor> descriptors,
-                  gimple *stmt)
+load_from_unmodified_param (struct ipa_func_body_info *fbi,
+                           vec<ipa_param_descriptor, va_gc> *descriptors,
+                           gimple *stmt)
 {
   int index;
   tree op1;
 
-  gcc_checking_assert (is_gimple_assign (stmt));
+  if (!gimple_assign_single_p (stmt))
+    return -1;
+
   op1 = gimple_assign_rhs1 (stmt);
   if (TREE_CODE (op1) != PARM_DECL)
     return -1;
@@ -886,40 +992,6 @@ load_from_param_1 (struct ipa_func_body_info *fbi,
   return index;
 }
 
-/* If STMT is an assignment that loads a value from an parameter declaration,
-   return the index of the parameter in ipa_node_params which has not been
-   modified.  Otherwise return -1.  */
-
-static int
-load_from_unmodified_param (struct ipa_func_body_info *fbi,
-                           vec<ipa_param_descriptor> descriptors,
-                           gimple *stmt)
-{
-  if (!gimple_assign_single_p (stmt))
-    return -1;
-
-  return load_from_param_1 (fbi, descriptors, stmt);
-}
-
-/* If STMT is an assignment that loads a value from an parameter declaration,
-   return the index of the parameter in ipa_node_params.  Otherwise return -1.  */
-
-static int
-load_from_param (struct ipa_func_body_info *fbi,
-                vec<ipa_param_descriptor> descriptors,
-                gimple *stmt)
-{
-  if (!is_gimple_assign (stmt))
-    return -1;
-
-  enum tree_code rhs_code = gimple_assign_rhs_code (stmt);
-  if ((get_gimple_rhs_class (rhs_code) != GIMPLE_SINGLE_RHS)
-      && (get_gimple_rhs_class (rhs_code) != GIMPLE_UNARY_RHS))
-    return -1;
-
-  return load_from_param_1 (fbi, descriptors, stmt);
-}
-
 /* Return true if memory reference REF (which must be a load through parameter
    with INDEX) loads data that are known to be unmodified in this function
    before reaching statement STMT.  */
@@ -932,29 +1004,24 @@ parm_ref_data_preserved_p (struct ipa_func_body_info *fbi,
   bool modified = false;
   ao_ref refd;
 
-  /* FIXME: FBI can be NULL if we are being called from outside
-     ipa_node_analysis or ipcp_transform_function, which currently happens
-     during inlining analysis.  It would be great to extend fbi's lifetime and
-     always have it.  Currently, we are just not afraid of too much walking in
-     that case.  */
-  if (fbi)
-    {
-      if (aa_overwalked (fbi))
-       return false;
-      paa = parm_bb_aa_status_for_bb (fbi, gimple_bb (stmt), index);
-      if (paa->ref_modified)
-       return false;
-    }
-  else
-    paa = NULL;
+  gcc_checking_assert (fbi);
+  paa = parm_bb_aa_status_for_bb (fbi, gimple_bb (stmt), index);
+  if (paa->ref_modified)
+    return false;
 
   gcc_checking_assert (gimple_vuse (stmt));
   ao_ref_init (&refd, ref);
   int walked = walk_aliased_vdefs (&refd, gimple_vuse (stmt), mark_modified,
-                                  &modified, NULL);
-  if (fbi)
-    fbi->aa_walked += walked;
-  if (paa && modified)
+                                  &modified, NULL, NULL,
+                                  fbi->aa_walk_budget + 1);
+  if (walked < 0)
+    {
+      modified = true;
+      fbi->aa_walk_budget = 0;
+    }
+  else
+    fbi->aa_walk_budget -= walked;
+  if (modified)
     paa->ref_modified = true;
   return !modified;
 }
@@ -974,8 +1041,7 @@ parm_ref_data_pass_through_p (struct ipa_func_body_info *fbi, int index,
      function because it is not goin to use it.  But do not cache the result
      either.  Also, no such calculations for non-pointers.  */
   if (!gimple_vuse (call)
-      || !POINTER_TYPE_P (TREE_TYPE (parm))
-      || aa_overwalked (fbi))
+      || !POINTER_TYPE_P (TREE_TYPE (parm)))
     return false;
 
   struct ipa_param_aa_status *paa = parm_bb_aa_status_for_bb (fbi,
@@ -986,8 +1052,15 @@ parm_ref_data_pass_through_p (struct ipa_func_body_info *fbi, int index,
 
   ao_ref_init_from_ptr_and_size (&refd, parm, NULL_TREE);
   int walked = walk_aliased_vdefs (&refd, gimple_vuse (call), mark_modified,
-                                  &modified, NULL);
-  fbi->aa_walked += walked;
+                                  &modified, NULL, NULL,
+                                  fbi->aa_walk_budget + 1);
+  if (walked < 0)
+    {
+      fbi->aa_walk_budget = 0;
+      modified = true;
+    }
+  else
+    fbi->aa_walk_budget -= walked;
   if (modified)
     paa->pt_modified = true;
   return !modified;
@@ -1010,18 +1083,17 @@ parm_ref_data_pass_through_p (struct ipa_func_body_info *fbi, int index,
 
 bool
 ipa_load_from_parm_agg (struct ipa_func_body_info *fbi,
-                       vec<ipa_param_descriptordescriptors,
+                       vec<ipa_param_descriptor, va_gc> *descriptors,
                        gimple *stmt, tree op, int *index_p,
-                       HOST_WIDE_INT *offset_p, HOST_WIDE_INT *size_p,
+                       HOST_WIDE_INT *offset_p, poly_int64 *size_p,
                        bool *by_ref_p, bool *guaranteed_unmodified)
 {
   int index;
-  HOST_WIDE_INT size, max_size;
+  HOST_WIDE_INT size;
   bool reverse;
-  tree base
-    = get_ref_base_and_extent (op, offset_p, &size, &max_size, &reverse);
+  tree base = get_ref_base_and_extent_hwi (op, offset_p, &size, &reverse);
 
-  if (max_size == -1 || max_size != size || *offset_p < 0)
+  if (!base)
     return false;
 
   if (DECL_P (base))
@@ -1089,6 +1161,67 @@ ipa_load_from_parm_agg (struct ipa_func_body_info *fbi,
   return false;
 }
 
+/* If STMT is an assignment that loads a value from a parameter declaration,
+   or from an aggregate passed as the parameter either by value or reference,
+   return the index of the parameter in ipa_node_params.  Otherwise return -1.
+
+   FBI holds gathered information about the function.  INFO describes
+   parameters of the function, STMT is the assignment statement.  If it is a
+   memory load from an aggregate, *OFFSET_P is filled with offset within the
+   aggregate, and *BY_REF_P specifies whether the aggregate is passed by
+   reference.  */
+
+static int
+load_from_unmodified_param_or_agg (struct ipa_func_body_info *fbi,
+                                  class ipa_node_params *info,
+                                  gimple *stmt,
+                                  HOST_WIDE_INT *offset_p,
+                                  bool *by_ref_p)
+{
+  int index = load_from_unmodified_param (fbi, info->descriptors, stmt);
+  poly_int64 size;
+
+  /* Load value from a parameter declaration.  */
+  if (index >= 0)
+    {
+      *offset_p = -1;
+      return index;
+    }
+
+  if (!gimple_assign_load_p (stmt))
+    return -1;
+
+  tree rhs = gimple_assign_rhs1 (stmt);
+
+  /* Skip memory reference containing VIEW_CONVERT_EXPR.  */
+  for (tree t = rhs; handled_component_p (t); t = TREE_OPERAND (t, 0))
+    if (TREE_CODE (t) == VIEW_CONVERT_EXPR)
+      return -1;
+
+  /* Skip memory reference containing bit-field.  */
+  if (TREE_CODE (rhs) == BIT_FIELD_REF
+      || contains_bitfld_component_ref_p (rhs))
+    return -1;
+
+  if (!ipa_load_from_parm_agg (fbi, info->descriptors, stmt, rhs, &index,
+                              offset_p, &size, by_ref_p))
+    return -1;
+
+  gcc_assert (!maybe_ne (tree_to_poly_int64 (TYPE_SIZE (TREE_TYPE (rhs))),
+                        size));
+  if (!*by_ref_p)
+    {
+      tree param_type = ipa_get_type (info, index);
+
+      if (!param_type || !AGGREGATE_TYPE_P (param_type))
+       return -1;
+    }
+  else if (TREE_THIS_VOLATILE (rhs))
+    return -1;
+
+  return index;
+}
+
 /* Given that an actual argument is an SSA_NAME (given in NAME) and is a result
    of an assignment statement STMT, try to determine whether we are actually
    handling any of the following cases and construct an appropriate jump
@@ -1144,16 +1277,15 @@ ipa_load_from_parm_agg (struct ipa_func_body_info *fbi,
 
 static void
 compute_complex_assign_jump_func (struct ipa_func_body_info *fbi,
-                                 struct ipa_node_params *info,
+                                 class ipa_node_params *info,
                                  struct ipa_jump_func *jfunc,
                                  gcall *call, gimple *stmt, tree name,
                                  tree param_type)
 {
-  HOST_WIDE_INT offset, size, max_size;
+  HOST_WIDE_INT offset, size;
   tree op1, tc_ssa, base, ssa;
   bool reverse;
   int index;
-  gimple *stmt2 = stmt;
 
   op1 = gimple_assign_rhs1 (stmt);
 
@@ -1162,16 +1294,13 @@ compute_complex_assign_jump_func (struct ipa_func_body_info *fbi,
       if (SSA_NAME_IS_DEFAULT_DEF (op1))
        index = ipa_get_param_decl_index (info, SSA_NAME_VAR (op1));
       else
-       {
-         index = load_from_param (fbi, info->descriptors,
-                                  SSA_NAME_DEF_STMT (op1));
-         stmt2 = SSA_NAME_DEF_STMT (op1);
-       }
+       index = load_from_unmodified_param (fbi, info->descriptors,
+                                           SSA_NAME_DEF_STMT (op1));
       tc_ssa = op1;
     }
   else
     {
-      index = load_from_param (fbi, info->descriptors, stmt);
+      index = load_from_unmodified_param (fbi, info->descriptors, stmt);
       tc_ssa = gimple_assign_lhs (stmt);
     }
 
@@ -1201,11 +1330,9 @@ compute_complex_assign_jump_func (struct ipa_func_body_info *fbi,
            break;
          }
        case GIMPLE_UNARY_RHS:
-         if (is_gimple_assign (stmt2)
-             && gimple_assign_rhs_class (stmt2) == GIMPLE_UNARY_RHS
-             && ! CONVERT_EXPR_CODE_P (gimple_assign_rhs_code (stmt2)))
+         if (!CONVERT_EXPR_CODE_P (gimple_assign_rhs_code (stmt)))
            ipa_set_jf_unary_pass_through (jfunc, index,
-                                          gimple_assign_rhs_code (stmt2));
+                                          gimple_assign_rhs_code (stmt));
        default:;
        }
       return;
@@ -1216,13 +1343,13 @@ compute_complex_assign_jump_func (struct ipa_func_body_info *fbi,
   op1 = TREE_OPERAND (op1, 0);
   if (TREE_CODE (TREE_TYPE (op1)) != RECORD_TYPE)
     return;
-  base = get_ref_base_and_extent (op1, &offset, &size, &max_size, &reverse);
-  if (TREE_CODE (base) != MEM_REF
-      /* If this is a varying address, punt.  */
-      || max_size == -1
-      || max_size != size)
+  base = get_ref_base_and_extent_hwi (op1, &offset, &size, &reverse);
+  offset_int mem_offset;
+  if (!base
+      || TREE_CODE (base) != MEM_REF
+      || !mem_ref_offset (base).is_constant (&mem_offset))
     return;
-  offset += mem_ref_offset (base).to_short_addr () * BITS_PER_UNIT;
+  offset += mem_offset.to_short_addr () * BITS_PER_UNIT;
   ssa = TREE_OPERAND (base, 0);
   if (TREE_CODE (ssa) != SSA_NAME
       || !SSA_NAME_IS_DEFAULT_DEF (ssa)
@@ -1250,7 +1377,7 @@ compute_complex_assign_jump_func (struct ipa_func_body_info *fbi,
 static tree
 get_ancestor_addr_info (gimple *assign, tree *obj_p, HOST_WIDE_INT *offset)
 {
-  HOST_WIDE_INT size, max_size;
+  HOST_WIDE_INT size;
   tree expr, parm, obj;
   bool reverse;
 
@@ -1262,13 +1389,12 @@ get_ancestor_addr_info (gimple *assign, tree *obj_p, HOST_WIDE_INT *offset)
     return NULL_TREE;
   expr = TREE_OPERAND (expr, 0);
   obj = expr;
-  expr = get_ref_base_and_extent (expr, offset, &size, &max_size, &reverse);
+  expr = get_ref_base_and_extent_hwi (expr, offset, &size, &reverse);
 
-  if (TREE_CODE (expr) != MEM_REF
-      /* If this is a varying address, punt.  */
-      || max_size == -1
-      || max_size != size
-      || *offset < 0)
+  offset_int mem_offset;
+  if (!expr
+      || TREE_CODE (expr) != MEM_REF
+      || !mem_ref_offset (expr).is_constant (&mem_offset))
     return NULL_TREE;
   parm = TREE_OPERAND (expr, 0);
   if (TREE_CODE (parm) != SSA_NAME
@@ -1276,7 +1402,7 @@ get_ancestor_addr_info (gimple *assign, tree *obj_p, HOST_WIDE_INT *offset)
       || TREE_CODE (SSA_NAME_VAR (parm)) != PARM_DECL)
     return NULL_TREE;
 
-  *offset += mem_ref_offset (expr).to_short_addr () * BITS_PER_UNIT;
+  *offset += mem_offset.to_short_addr () * BITS_PER_UNIT;
   *obj_p = obj;
   return expr;
 }
@@ -1305,7 +1431,7 @@ get_ancestor_addr_info (gimple *assign, tree *obj_p, HOST_WIDE_INT *offset)
 
 static void
 compute_complex_ancestor_jump_func (struct ipa_func_body_info *fbi,
-                                   struct ipa_node_params *info,
+                                   class ipa_node_params *info,
                                    struct ipa_jump_func *jfunc,
                                    gcall *call, gphi *phi)
 {
@@ -1399,11 +1525,11 @@ type_like_member_ptr_p (tree type, tree *method_ptr, tree *delta)
 }
 
 /* If RHS is an SSA_NAME and it is defined by a simple copy assign statement,
-   return the rhs of its defining statement.  Otherwise return RHS as it
-   is.  */
+   return the rhs of its defining statement, and this statement is stored in
+   *RHS_STMT.  Otherwise return RHS as it is.  */
 
 static inline tree
-get_ssa_def_if_simple_copy (tree rhs)
+get_ssa_def_if_simple_copy (tree rhs, gimple **rhs_stmt)
 {
   while (TREE_CODE (rhs) == SSA_NAME && !SSA_NAME_IS_DEFAULT_DEF (rhs))
     {
@@ -1413,100 +1539,324 @@ get_ssa_def_if_simple_copy (tree rhs)
        rhs = gimple_assign_rhs1 (def_stmt);
       else
        break;
+      *rhs_stmt = def_stmt;
     }
   return rhs;
 }
 
-/* Simple linked list, describing known contents of an aggregate beforere
-   call.  */
+/* Simple linked list, describing contents of an aggregate before call.  */
 
 struct ipa_known_agg_contents_list
 {
   /* Offset and size of the described part of the aggregate.  */
   HOST_WIDE_INT offset, size;
-  /* Known constant value or NULL if the contents is known to be unknown.  */
-  tree constant;
+
+  /* Type of the described part of the aggregate.  */
+  tree type;
+
+  /* Known constant value or jump function data describing contents.  */
+  struct ipa_load_agg_data value;
+
   /* Pointer to the next structure in the list.  */
   struct ipa_known_agg_contents_list *next;
 };
 
-/* Find the proper place in linked list of ipa_known_agg_contents_list
-   structures where to put a new one with the given LHS_OFFSET and LHS_SIZE,
-   unless there is a partial overlap, in which case return NULL, or such
-   element is already there, in which case set *ALREADY_THERE to true.  */
+/* Add an aggregate content item into a linked list of
+   ipa_known_agg_contents_list structure, in which all elements
+   are sorted ascendingly by offset.  */
 
-static struct ipa_known_agg_contents_list **
-get_place_in_agg_contents_list (struct ipa_known_agg_contents_list **list,
-                               HOST_WIDE_INT lhs_offset,
-                               HOST_WIDE_INT lhs_size,
-                               bool *already_there)
+static inline void
+add_to_agg_contents_list (struct ipa_known_agg_contents_list **plist,
+                         struct ipa_known_agg_contents_list *item)
 {
-  struct ipa_known_agg_contents_list **p = list;
-  while (*p && (*p)->offset < lhs_offset)
+  struct ipa_known_agg_contents_list *list = *plist;
+
+  for (; list; list = list->next)
     {
-      if ((*p)->offset + (*p)->size > lhs_offset)
-       return NULL;
-      p = &(*p)->next;
+      if (list->offset >= item->offset)
+       break;
+
+      plist = &list->next;
     }
 
-  if (*p && (*p)->offset < lhs_offset + lhs_size)
+  item->next = list;
+  *plist = item;
+}
+
+/* Check whether a given aggregate content is clobbered by certain element in
+   a linked list of ipa_known_agg_contents_list.  */
+
+static inline bool
+clobber_by_agg_contents_list_p (struct ipa_known_agg_contents_list *list,
+                               struct ipa_known_agg_contents_list *item)
+{
+  for (; list; list = list->next)
     {
-      if ((*p)->offset == lhs_offset && (*p)->size == lhs_size)
-       /* We already know this value is subsequently overwritten with
-          something else.  */
-       *already_there = true;
-      else
-       /* Otherwise this is a partial overlap which we cannot
-          represent.  */
-       return NULL;
+      if (list->offset >= item->offset)
+       return list->offset < item->offset + item->size;
+
+      if (list->offset + list->size > item->offset)
+       return true;
     }
-  return p;
+
+  return false;
 }
 
 /* Build aggregate jump function from LIST, assuming there are exactly
-   CONST_COUNT constant entries there and that th offset of the passed argument
+   VALUE_COUNT entries there and that offset of the passed argument
    is ARG_OFFSET and store it into JFUNC.  */
 
 static void
 build_agg_jump_func_from_list (struct ipa_known_agg_contents_list *list,
-                              int const_count, HOST_WIDE_INT arg_offset,
+                              int value_count, HOST_WIDE_INT arg_offset,
                               struct ipa_jump_func *jfunc)
 {
-  vec_alloc (jfunc->agg.items, const_count);
-  while (list)
+  vec_alloc (jfunc->agg.items, value_count);
+  for (; list; list = list->next)
     {
-      if (list->constant)
+      struct ipa_agg_jf_item item;
+      tree operand = list->value.pass_through.operand;
+
+      if (list->value.pass_through.formal_id >= 0)
+       {
+         /* Content value is derived from some formal paramerter.  */
+         if (list->value.offset >= 0)
+           item.jftype = IPA_JF_LOAD_AGG;
+         else
+           item.jftype = IPA_JF_PASS_THROUGH;
+
+         item.value.load_agg = list->value;
+         if (operand)
+           item.value.pass_through.operand
+             = unshare_expr_without_location (operand);
+       }
+      else if (operand)
        {
-         struct ipa_agg_jf_item item;
-         item.offset = list->offset - arg_offset;
-         gcc_assert ((item.offset % BITS_PER_UNIT) == 0);
-         item.value = unshare_expr_without_location (list->constant);
-         jfunc->agg.items->quick_push (item);
+         /* Content value is known constant.  */
+         item.jftype = IPA_JF_CONST;
+         item.value.constant = unshare_expr_without_location (operand);
        }
-      list = list->next;
+      else
+       continue;
+
+      item.type = list->type;
+      gcc_assert (tree_to_shwi (TYPE_SIZE (list->type)) == list->size);
+
+      item.offset = list->offset - arg_offset;
+      gcc_assert ((item.offset % BITS_PER_UNIT) == 0);
+
+      jfunc->agg.items->quick_push (item);
     }
 }
 
-/* Traverse statements from CALL backwards, scanning whether an aggregate given
-   in ARG is filled in with constant values.  ARG can either be an aggregate
-   expression or a pointer to an aggregate.  ARG_TYPE is the type of the
-   aggregate.  JFUNC is the jump function into which the constants are
-   subsequently stored.  */
+/* Given an assignment statement STMT, try to collect information into
+   AGG_VALUE that will be used to construct jump function for RHS of the
+   assignment, from which content value of an aggregate part comes.
+
+   Besides constant and simple pass-through jump functions, also try to
+   identify whether it matches the following pattern that can be described by
+   a load-value-from-aggregate jump function, which is a derivative of simple
+   pass-through jump function.
+
+     foo (int *p)
+     {
+       ...
+
+       *(q_5 + 4) = *(p_3(D) + 28) op 1;
+       bar (q_5);
+     }
+
+   Here IPA_LOAD_AGG_DATA data structure is informative enough to describe
+   constant, simple pass-through and load-vale-from-aggregate. If value
+   is constant, it will be kept in field OPERAND, and field FORMAL_ID is
+   set to -1. For simple pass-through and load-value-from-aggregate, field
+   FORMAL_ID specifies the related formal parameter index, and field
+   OFFSET can be used to distinguish them, -1 means simple pass-through,
+   otherwise means load-value-from-aggregate.  */
 
 static void
-determine_locally_known_aggregate_parts (gcall *call, tree arg,
-                                        tree arg_type,
-                                        struct ipa_jump_func *jfunc)
+analyze_agg_content_value (struct ipa_func_body_info *fbi,
+                          struct ipa_load_agg_data *agg_value,
+                          gimple *stmt)
+{
+  tree lhs = gimple_assign_lhs (stmt);
+  tree rhs1 = gimple_assign_rhs1 (stmt);
+  enum tree_code code;
+  int index = -1;
+
+  /* Initialize jump function data for the aggregate part.  */
+  memset (agg_value, 0, sizeof (*agg_value));
+  agg_value->pass_through.operation = NOP_EXPR;
+  agg_value->pass_through.formal_id = -1;
+  agg_value->offset = -1;
+
+  if (AGGREGATE_TYPE_P (TREE_TYPE (lhs))  /* TODO: Support aggregate type.  */
+      || TREE_THIS_VOLATILE (lhs)
+      || TREE_CODE (lhs) == BIT_FIELD_REF
+      || contains_bitfld_component_ref_p (lhs))
+    return;
+
+  /* Skip SSA copies.  */
+  while (gimple_assign_rhs_class (stmt) == GIMPLE_SINGLE_RHS)
+    {
+      if (TREE_CODE (rhs1) != SSA_NAME || SSA_NAME_IS_DEFAULT_DEF (rhs1))
+       break;
+
+      stmt = SSA_NAME_DEF_STMT (rhs1);
+      if (!is_gimple_assign (stmt))
+       return;
+
+      rhs1 = gimple_assign_rhs1 (stmt);
+    }
+
+  code = gimple_assign_rhs_code (stmt);
+  switch (gimple_assign_rhs_class (stmt))
+    {
+    case GIMPLE_SINGLE_RHS:
+      if (is_gimple_ip_invariant (rhs1))
+       {
+         agg_value->pass_through.operand = rhs1;
+         return;
+       }
+      code = NOP_EXPR;
+      break;
+
+    case GIMPLE_UNARY_RHS:
+      /* NOTE: A GIMPLE_UNARY_RHS operation might not be tcc_unary
+        (truth_not_expr is example), GIMPLE_BINARY_RHS does not imply
+        tcc_binary, this subtleness is somewhat misleading.
+
+        Since tcc_unary is widely used in IPA-CP code to check an operation
+        with one operand, here we only allow tc_unary operation to avoid
+        possible problem.  Then we can use (opclass == tc_unary) or not to
+        distinguish unary and binary.  */
+      if (TREE_CODE_CLASS (code) != tcc_unary || CONVERT_EXPR_CODE_P (code))
+       return;
+
+      rhs1 = get_ssa_def_if_simple_copy (rhs1, &stmt);
+      break;
+
+    case GIMPLE_BINARY_RHS:
+      {
+       gimple *rhs1_stmt = stmt;
+       gimple *rhs2_stmt = stmt;
+       tree rhs2 = gimple_assign_rhs2 (stmt);
+
+       rhs1 = get_ssa_def_if_simple_copy (rhs1, &rhs1_stmt);
+       rhs2 = get_ssa_def_if_simple_copy (rhs2, &rhs2_stmt);
+
+       if (is_gimple_ip_invariant (rhs2))
+         {
+           agg_value->pass_through.operand = rhs2;
+           stmt = rhs1_stmt;
+         }
+       else if (is_gimple_ip_invariant (rhs1))
+         {
+           if (TREE_CODE_CLASS (code) == tcc_comparison)
+             code = swap_tree_comparison (code);
+           else if (!commutative_tree_code (code))
+             return;
+
+           agg_value->pass_through.operand = rhs1;
+           stmt = rhs2_stmt;
+           rhs1 = rhs2;
+         }
+       else
+         return;
+
+       if (TREE_CODE_CLASS (code) != tcc_comparison
+           && !useless_type_conversion_p (TREE_TYPE (lhs), TREE_TYPE (rhs1)))
+         return;
+      }
+      break;
+
+    default:
+      return;
+  }
+
+  if (TREE_CODE (rhs1) != SSA_NAME)
+    index = load_from_unmodified_param_or_agg (fbi, fbi->info, stmt,
+                                              &agg_value->offset,
+                                              &agg_value->by_ref);
+  else if (SSA_NAME_IS_DEFAULT_DEF (rhs1))
+    index = ipa_get_param_decl_index (fbi->info, SSA_NAME_VAR (rhs1));
+
+  if (index >= 0)
+    {
+      if (agg_value->offset >= 0)
+       agg_value->type = TREE_TYPE (rhs1);
+      agg_value->pass_through.formal_id = index;
+      agg_value->pass_through.operation = code;
+    }
+  else
+    agg_value->pass_through.operand = NULL_TREE;
+}
+
+/* If STMT is a memory store to the object whose address is BASE, extract
+   information (offset, size, and value) into CONTENT, and return true,
+   otherwise we conservatively assume the whole object is modified with
+   unknown content, and return false.  CHECK_REF means that access to object
+   is expected to be in form of MEM_REF expression.  */
+
+static bool
+extract_mem_content (struct ipa_func_body_info *fbi,
+                    gimple *stmt, tree base, bool check_ref,
+                    struct ipa_known_agg_contents_list *content)
 {
-  struct ipa_known_agg_contents_list *list = NULL;
-  int item_count = 0, const_count = 0;
+  HOST_WIDE_INT lhs_offset, lhs_size;
+  bool reverse;
+
+  if (!is_gimple_assign (stmt))
+    return false;
+
+  tree lhs = gimple_assign_lhs (stmt);
+  tree lhs_base = get_ref_base_and_extent_hwi (lhs, &lhs_offset, &lhs_size,
+                                              &reverse);
+  if (!lhs_base)
+    return false;
+
+  if (check_ref)
+    {
+      if (TREE_CODE (lhs_base) != MEM_REF
+         || TREE_OPERAND (lhs_base, 0) != base
+         || !integer_zerop (TREE_OPERAND (lhs_base, 1)))
+       return false;
+    }
+  else if (lhs_base != base)
+    return false;
+
+  content->offset = lhs_offset;
+  content->size = lhs_size;
+  content->type = TREE_TYPE (lhs);
+  content->next = NULL;
+
+  analyze_agg_content_value (fbi, &content->value, stmt);
+  return true;
+}
+
+/* Traverse statements from CALL backwards, scanning whether an aggregate given
+   in ARG is filled in constants or values that are derived from caller's
+   formal parameter in the way described by some kinds of jump functions.  FBI
+   is the context of the caller function for interprocedural analysis.  ARG can
+   either be an aggregate expression or a pointer to an aggregate.  ARG_TYPE is
+   the type of the aggregate, JFUNC is the jump function for the aggregate.  */
+
+static void
+determine_known_aggregate_parts (struct ipa_func_body_info *fbi,
+                                gcall *call, tree arg,
+                                tree arg_type,
+                                struct ipa_jump_func *jfunc)
+{
+  struct ipa_known_agg_contents_list *list = NULL, *all_list = NULL;
+  bitmap visited = NULL;
+  int item_count = 0, value_count = 0;
   HOST_WIDE_INT arg_offset, arg_size;
-  gimple_stmt_iterator gsi;
   tree arg_base;
   bool check_ref, by_ref;
   ao_ref r;
+  int max_agg_items = opt_for_fn (fbi->node->decl, param_ipa_max_agg_items);
 
-  if (PARAM_VALUE (PARAM_IPA_MAX_AGG_ITEMS) == 0)
+  if (max_agg_items == 0)
     return;
 
   /* The function operates in three stages.  First, we prepare check_ref, r,
@@ -1519,7 +1869,8 @@ determine_locally_known_aggregate_parts (gcall *call, tree arg,
       if (TREE_CODE (arg) == SSA_NAME)
        {
          tree type_size;
-          if (!tree_fits_uhwi_p (TYPE_SIZE (TREE_TYPE (arg_type))))
+          if (!tree_fits_uhwi_p (TYPE_SIZE (TREE_TYPE (arg_type)))
+             || !POINTER_TYPE_P (TREE_TYPE (arg)))
             return;
          check_ref = true;
          arg_base = arg;
@@ -1530,15 +1881,12 @@ determine_locally_known_aggregate_parts (gcall *call, tree arg,
        }
       else if (TREE_CODE (arg) == ADDR_EXPR)
        {
-         HOST_WIDE_INT arg_max_size;
          bool reverse;
 
          arg = TREE_OPERAND (arg, 0);
-         arg_base = get_ref_base_and_extent (arg, &arg_offset, &arg_size,
-                                             &arg_max_size, &reverse);
-         if (arg_max_size == -1
-             || arg_max_size != arg_size
-             || arg_offset < 0)
+         arg_base = get_ref_base_and_extent_hwi (arg, &arg_offset,
+                                                 &arg_size, &reverse);
+         if (!arg_base)
            return;
          if (DECL_P (arg_base))
            {
@@ -1553,109 +1901,87 @@ determine_locally_known_aggregate_parts (gcall *call, tree arg,
     }
   else
     {
-      HOST_WIDE_INT arg_max_size;
       bool reverse;
 
       gcc_checking_assert (AGGREGATE_TYPE_P (TREE_TYPE (arg)));
 
       by_ref = false;
       check_ref = false;
-      arg_base = get_ref_base_and_extent (arg, &arg_offset, &arg_size,
-                                         &arg_max_size, &reverse);
-      if (arg_max_size == -1
-         || arg_max_size != arg_size
-         || arg_offset < 0)
+      arg_base = get_ref_base_and_extent_hwi (arg, &arg_offset,
+                                             &arg_size, &reverse);
+      if (!arg_base)
        return;
 
       ao_ref_init (&r, arg);
     }
 
-  /* Second stage walks back the BB, looks at individual statements and as long
-     as it is confident of how the statements affect contents of the
-     aggregates, it builds a sorted linked list of ipa_agg_jf_list structures
-     describing it.  */
-  gsi = gsi_for_stmt (call);
-  gsi_prev (&gsi);
-  for (; !gsi_end_p (gsi); gsi_prev (&gsi))
-    {
-      struct ipa_known_agg_contents_list *n, **p;
-      gimple *stmt = gsi_stmt (gsi);
-      HOST_WIDE_INT lhs_offset, lhs_size, lhs_max_size;
-      tree lhs, rhs, lhs_base;
-      bool reverse;
+  /* Second stage traverses virtual SSA web backwards starting from the call
+     statement, only looks at individual dominating virtual operand (its
+     definition dominates the call), as long as it is confident that content
+     of the aggregate is affected by definition of the virtual operand, it
+     builds a sorted linked list of ipa_agg_jf_list describing that.  */
 
-      if (!stmt_may_clobber_ref_p_1 (stmt, &r))
-       continue;
-      if (!gimple_assign_single_p (stmt))
-       break;
+  for (tree dom_vuse = gimple_vuse (call); dom_vuse;)
+    {
+      gimple *stmt = SSA_NAME_DEF_STMT (dom_vuse);
 
-      lhs = gimple_assign_lhs (stmt);
-      rhs = gimple_assign_rhs1 (stmt);
-      if (!is_gimple_reg_type (TREE_TYPE (rhs))
-         || TREE_CODE (lhs) == BIT_FIELD_REF
-         || contains_bitfld_component_ref_p (lhs))
-       break;
-
-      lhs_base = get_ref_base_and_extent (lhs, &lhs_offset, &lhs_size,
-                                         &lhs_max_size, &reverse);
-      if (lhs_max_size == -1
-         || lhs_max_size != lhs_size)
-       break;
-
-      if (check_ref)
+      if (gimple_code (stmt) == GIMPLE_PHI)
        {
-         if (TREE_CODE (lhs_base) != MEM_REF
-             || TREE_OPERAND (lhs_base, 0) != arg_base
-             || !integer_zerop (TREE_OPERAND (lhs_base, 1)))
-           break;
+         dom_vuse = get_continuation_for_phi (stmt, &r, true,
+                                              fbi->aa_walk_budget,
+                                              &visited, false, NULL, NULL);
+         continue;
        }
-      else if (lhs_base != arg_base)
+
+      if (stmt_may_clobber_ref_p_1 (stmt, &r))
        {
-         if (DECL_P (lhs_base))
-           continue;
-         else
+         struct ipa_known_agg_contents_list *content
+                       = XALLOCA (struct ipa_known_agg_contents_list);
+
+         if (!extract_mem_content (fbi, stmt, arg_base, check_ref, content))
            break;
-       }
 
-      bool already_there = false;
-      p = get_place_in_agg_contents_list (&list, lhs_offset, lhs_size,
-                                         &already_there);
-      if (!p)
-       break;
-      if (already_there)
-       continue;
+         /* Now we get a dominating virtual operand, and need to check
+            whether its value is clobbered any other dominating one.  */
+         if ((content->value.pass_through.formal_id >= 0
+              || content->value.pass_through.operand)
+             && !clobber_by_agg_contents_list_p (all_list, content))
+           {
+             struct ipa_known_agg_contents_list *copy
+                       = XALLOCA (struct ipa_known_agg_contents_list);
 
-      rhs = get_ssa_def_if_simple_copy (rhs);
-      n = XALLOCA (struct ipa_known_agg_contents_list);
-      n->size = lhs_size;
-      n->offset = lhs_offset;
-      if (is_gimple_ip_invariant (rhs))
-       {
-         n->constant = rhs;
-         const_count++;
+             /* Add to the list consisting of only dominating virtual
+                operands, whose definitions can finally reach the call.  */
+             add_to_agg_contents_list (&list, (*copy = *content, copy));
+
+             if (++value_count == max_agg_items)
+               break;
+           }
+
+         /* Add to the list consisting of all dominating virtual operands.  */
+         add_to_agg_contents_list (&all_list, content);
+
+         if (++item_count == 2 * max_agg_items)
+           break;
        }
-      else
-       n->constant = NULL_TREE;
-      n->next = *p;
-      *p = n;
+      dom_vuse = gimple_vuse (stmt);
+   }
 
-      item_count++;
-      if (const_count == PARAM_VALUE (PARAM_IPA_MAX_AGG_ITEMS)
-         || item_count == 2 * PARAM_VALUE (PARAM_IPA_MAX_AGG_ITEMS))
-       break;
-    }
+  if (visited)
+    BITMAP_FREE (visited);
 
   /* Third stage just goes over the list and creates an appropriate vector of
-     ipa_agg_jf_item structures out of it, of sourse only if there are
-     any known constants to begin with.  */
+     ipa_agg_jf_item structures out of it, of course only if there are
+     any meaningful items to begin with.  */
 
-  if (const_count)
+  if (value_count)
     {
       jfunc->agg.by_ref = by_ref;
-      build_agg_jump_func_from_list (list, const_count, arg_offset, jfunc);
+      build_agg_jump_func_from_list (list, value_count, arg_offset, jfunc);
     }
 }
 
+
 /* Return the Ith param type of callee associated with call graph
    edge E.  */
 
@@ -1690,6 +2016,87 @@ ipa_get_callee_param_type (struct cgraph_edge *e, int i)
   return NULL;
 }
 
+/* Return ipa_bits with VALUE and MASK values, which can be either a newly
+   allocated structure or a previously existing one shared with other jump
+   functions and/or transformation summaries.  */
+
+ipa_bits *
+ipa_get_ipa_bits_for_value (const widest_int &value, const widest_int &mask)
+{
+  ipa_bits tmp;
+  tmp.value = value;
+  tmp.mask = mask;
+
+  ipa_bits **slot = ipa_bits_hash_table->find_slot (&tmp, INSERT);
+  if (*slot)
+    return *slot;
+
+  ipa_bits *res = ggc_alloc<ipa_bits> ();
+  res->value = value;
+  res->mask = mask;
+  *slot = res;
+
+  return res;
+}
+
+/* Assign to JF a pointer to ipa_bits structure with VALUE and MASK.  Use hash
+   table in order to avoid creating multiple same ipa_bits structures.  */
+
+static void
+ipa_set_jfunc_bits (ipa_jump_func *jf, const widest_int &value,
+                   const widest_int &mask)
+{
+  jf->bits = ipa_get_ipa_bits_for_value (value, mask);
+}
+
+/* Return a pointer to a value_range just like *TMP, but either find it in
+   ipa_vr_hash_table or allocate it in GC memory.  TMP->equiv must be NULL.  */
+
+static value_range *
+ipa_get_value_range (value_range *tmp)
+{
+  value_range **slot = ipa_vr_hash_table->find_slot (tmp, INSERT);
+  if (*slot)
+    return *slot;
+
+  value_range *vr = ggc_alloc<value_range> ();
+  *vr = *tmp;
+  *slot = vr;
+
+  return vr;
+}
+
+/* Return a pointer to a value range consisting of TYPE, MIN, MAX and an empty
+   equiv set. Use hash table in order to avoid creating multiple same copies of
+   value_ranges.  */
+
+static value_range *
+ipa_get_value_range (enum value_range_kind kind, tree min, tree max)
+{
+  value_range tmp (min, max, kind);
+  return ipa_get_value_range (&tmp);
+}
+
+/* Assign to JF a pointer to a value_range structure with TYPE, MIN and MAX and
+   a NULL equiv bitmap.  Use hash table in order to avoid creating multiple
+   same value_range structures.  */
+
+static void
+ipa_set_jfunc_vr (ipa_jump_func *jf, enum value_range_kind type,
+                 tree min, tree max)
+{
+  jf->m_vr = ipa_get_value_range (type, min, max);
+}
+
+/* Assign to JF a pointer to a value_range just like TMP but either fetch a
+   copy from ipa_vr_hash_table or allocate a new on in GC memory.  */
+
+static void
+ipa_set_jfunc_vr (ipa_jump_func *jf, value_range *tmp)
+{
+  jf->m_vr = ipa_get_value_range (tmp);
+}
+
 /* Compute jump function for all arguments of callsite CS and insert the
    information in the jump_functions array in the ipa_edge_args corresponding
    to this callsite.  */
@@ -1698,8 +2105,8 @@ static void
 ipa_compute_jump_functions_for_edge (struct ipa_func_body_info *fbi,
                                     struct cgraph_edge *cs)
 {
-  struct ipa_node_params *info = IPA_NODE_REF (cs->caller);
-  struct ipa_edge_args *args = IPA_EDGE_REF (cs);
+  class ipa_node_params *info = IPA_NODE_REF (cs->caller);
+  class ipa_edge_args *args = IPA_EDGE_REF_GET_CREATE (cs);
   gcall *call = cs->call_stmt;
   int n, arg_num = gimple_call_num_args (call);
   bool useful_context = false;
@@ -1723,10 +2130,11 @@ ipa_compute_jump_functions_for_edge (struct ipa_func_body_info *fbi,
       if (flag_devirtualize && POINTER_TYPE_P (TREE_TYPE (arg)))
        {
          tree instance;
-         struct ipa_polymorphic_call_context context (cs->caller->decl,
+         class ipa_polymorphic_call_context context (cs->caller->decl,
                                                       arg, cs->call_stmt,
                                                       &instance);
-         context.get_dynamic_type (instance, arg, NULL, cs->call_stmt);
+         context.get_dynamic_type (instance, arg, NULL, cs->call_stmt,
+                                   &fbi->aa_walk_budget);
          *ipa_get_ith_polymorhic_call_context (args, n) = context;
          if (!context.useless_p ())
            useful_context = true;
@@ -1746,74 +2154,60 @@ ipa_compute_jump_functions_for_edge (struct ipa_func_body_info *fbi,
 
          if (addr_nonzero)
            {
-             jfunc->vr_known = true;
-             jfunc->m_vr.type = VR_ANTI_RANGE;
-             jfunc->m_vr.min = build_int_cst (TREE_TYPE (arg), 0);
-             jfunc->m_vr.max = build_int_cst (TREE_TYPE (arg), 0);
-             jfunc->m_vr.equiv = NULL;
+             tree z = build_int_cst (TREE_TYPE (arg), 0);
+             ipa_set_jfunc_vr (jfunc, VR_ANTI_RANGE, z, z);
            }
          else
-           gcc_assert (!jfunc->vr_known);
+           gcc_assert (!jfunc->m_vr);
        }
       else
        {
          wide_int min, max;
-         value_range_type type;
+         value_range_kind kind;
          if (TREE_CODE (arg) == SSA_NAME
              && param_type
-             && (type = get_range_info (arg, &min, &max))
-             && (type == VR_RANGE || type == VR_ANTI_RANGE))
+             && (kind = get_range_info (arg, &min, &max))
+             && (kind == VR_RANGE || kind == VR_ANTI_RANGE))
            {
-             value_range vr;
-
-             vr.type = type;
-             vr.min = wide_int_to_tree (TREE_TYPE (arg), min);
-             vr.max = wide_int_to_tree (TREE_TYPE (arg), max);
-             vr.equiv = NULL;
-             extract_range_from_unary_expr (&jfunc->m_vr,
-                                            NOP_EXPR,
-                                            param_type,
-                                            &vr, TREE_TYPE (arg));
-             if (jfunc->m_vr.type == VR_RANGE
-                 || jfunc->m_vr.type == VR_ANTI_RANGE)
-               jfunc->vr_known = true;
+             value_range resvr;
+             value_range tmpvr (wide_int_to_tree (TREE_TYPE (arg), min),
+                                wide_int_to_tree (TREE_TYPE (arg), max),
+                                kind);
+             range_fold_unary_expr (&resvr, NOP_EXPR, param_type,
+                                    &tmpvr, TREE_TYPE (arg));
+             if (!resvr.undefined_p () && !resvr.varying_p ())
+               ipa_set_jfunc_vr (jfunc, &resvr);
              else
-               jfunc->vr_known = false;
+               gcc_assert (!jfunc->m_vr);
            }
          else
-           gcc_assert (!jfunc->vr_known);
+           gcc_assert (!jfunc->m_vr);
        }
 
       if (INTEGRAL_TYPE_P (TREE_TYPE (arg))
          && (TREE_CODE (arg) == SSA_NAME || TREE_CODE (arg) == INTEGER_CST))
        {
-         jfunc->bits.known = true;
-         
          if (TREE_CODE (arg) == SSA_NAME)
-           {
-             jfunc->bits.value = 0;
-             jfunc->bits.mask = widest_int::from (get_nonzero_bits (arg),
-                                                  TYPE_SIGN (TREE_TYPE (arg)));
-           }
+           ipa_set_jfunc_bits (jfunc, 0,
+                               widest_int::from (get_nonzero_bits (arg),
+                                                 TYPE_SIGN (TREE_TYPE (arg))));
          else
-           {
-             jfunc->bits.value = wi::to_widest (arg);
-             jfunc->bits.mask = 0;
-           }
+           ipa_set_jfunc_bits (jfunc, wi::to_widest (arg), 0);
        }
       else if (POINTER_TYPE_P (TREE_TYPE (arg)))
        {
          unsigned HOST_WIDE_INT bitpos;
          unsigned align;
 
-         jfunc->bits.known = true;
          get_pointer_alignment_1 (arg, &align, &bitpos);
-         jfunc->bits.mask = wi::mask<widest_int>(TYPE_PRECISION (TREE_TYPE (arg)), false)
-                            .and_not (align / BITS_PER_UNIT - 1);
-         jfunc->bits.value = bitpos / BITS_PER_UNIT;
+         widest_int mask = wi::bit_and_not
+           (wi::mask<widest_int> (TYPE_PRECISION (TREE_TYPE (arg)), false),
+            align / BITS_PER_UNIT - 1);
+         widest_int value = bitpos / BITS_PER_UNIT;
+         ipa_set_jfunc_bits (jfunc, value, mask);
        }
       else
-       gcc_assert (!jfunc->bits.known);
+       gcc_assert (!jfunc->bits);
 
       if (is_gimple_ip_invariant (arg)
          || (VAR_P (arg)
@@ -1860,7 +2254,7 @@ ipa_compute_jump_functions_for_edge (struct ipa_func_body_info *fbi,
            }
        }
 
-      /* If ARG is pointer, we can not use its type to determine the type of aggregate
+      /* If ARG is pointer, we cannot use its type to determine the type of aggregate
         passed (because type conversions are ignored in gimple).  Usually we can
         safely get type from function declaration, but in case of K&R prototypes or
         variadic functions we can try our luck with type of the pointer passed.
@@ -1875,7 +2269,7 @@ ipa_compute_jump_functions_for_edge (struct ipa_func_body_info *fbi,
              || !ipa_get_jf_ancestor_agg_preserved (jfunc))
          && (AGGREGATE_TYPE_P (TREE_TYPE (arg))
              || POINTER_TYPE_P (param_type)))
-       determine_locally_known_aggregate_parts (call, arg, param_type, jfunc);
+       determine_known_aggregate_parts (fbi, call, arg, param_type, jfunc);
     }
   if (!useful_context)
     vec_free (args->polymorphic_call_contexts);
@@ -1897,7 +2291,7 @@ ipa_compute_jump_functions_for_bb (struct ipa_func_body_info *fbi, basic_block b
 
       if (callee)
        {
-         callee->ultimate_alias_target ();
+         callee = callee->ultimate_alias_target ();
          /* We do not need to bother analyzing calls to unknown functions
             unless they may become known during lto/whopr.  */
          if (!callee->definition && !flag_lto)
@@ -1973,11 +2367,12 @@ ipa_is_ssa_with_stmt_def (tree t)
 
 /* Find the indirect call graph edge corresponding to STMT and mark it as a
    call to a parameter number PARAM_INDEX.  NODE is the caller.  Return the
-   indirect call graph edge.  */
+   indirect call graph edge.
+   If POLYMORPHIC is true record is as a destination of polymorphic call.  */
 
 static struct cgraph_edge *
 ipa_note_param_call (struct cgraph_node *node, int param_index,
-                    gcall *stmt)
+                    gcall *stmt, bool polymorphic)
 {
   struct cgraph_edge *cs;
 
@@ -1986,6 +2381,11 @@ ipa_note_param_call (struct cgraph_node *node, int param_index,
   cs->indirect_info->agg_contents = 0;
   cs->indirect_info->member_ptr = 0;
   cs->indirect_info->guaranteed_unmodified = 0;
+  ipa_set_param_used_by_indirect_call (IPA_NODE_REF (node),
+                                         param_index, true);
+  if (cs->indirect_info->polymorphic || polymorphic)
+    ipa_set_param_used_by_polymorphic_call
+           (IPA_NODE_REF (node), param_index, true);
   return cs;
 }
 
@@ -2052,7 +2452,7 @@ static void
 ipa_analyze_indirect_call_uses (struct ipa_func_body_info *fbi, gcall *call,
                                tree target)
 {
-  struct ipa_node_params *info = fbi->info;
+  class ipa_node_params *info = fbi->info;
   HOST_WIDE_INT offset;
   bool by_ref;
 
@@ -2061,7 +2461,7 @@ ipa_analyze_indirect_call_uses (struct ipa_func_body_info *fbi, gcall *call,
       tree var = SSA_NAME_VAR (target);
       int index = ipa_get_param_decl_index (info, var);
       if (index >= 0)
-       ipa_note_param_call (fbi->node, index, call);
+       ipa_note_param_call (fbi->node, index, call, false);
       return;
     }
 
@@ -2073,7 +2473,8 @@ ipa_analyze_indirect_call_uses (struct ipa_func_body_info *fbi, gcall *call,
                                 gimple_assign_rhs1 (def), &index, &offset,
                                 NULL, &by_ref, &guaranteed_unmodified))
     {
-      struct cgraph_edge *cs = ipa_note_param_call (fbi->node, index, call);
+      struct cgraph_edge *cs = ipa_note_param_call (fbi->node, index,
+                                                   call, false);
       cs->indirect_info->offset = offset;
       cs->indirect_info->agg_contents = 1;
       cs->indirect_info->by_ref = by_ref;
@@ -2174,7 +2575,8 @@ ipa_analyze_indirect_call_uses (struct ipa_func_body_info *fbi, gcall *call,
   if (index >= 0
       && parm_preserved_before_stmt_p (fbi, index, call, rec))
     {
-      struct cgraph_edge *cs = ipa_note_param_call (fbi->node, index, call);
+      struct cgraph_edge *cs = ipa_note_param_call (fbi->node, index,
+                                                   call, false);
       cs->indirect_info->offset = offset;
       cs->indirect_info->agg_contents = 1;
       cs->indirect_info->member_ptr = 1;
@@ -2203,23 +2605,21 @@ ipa_analyze_virtual_call_uses (struct ipa_func_body_info *fbi,
   if (TREE_CODE (obj) != SSA_NAME)
     return;
 
-  struct ipa_node_params *info = fbi->info;
+  class ipa_node_params *info = fbi->info;
   if (SSA_NAME_IS_DEFAULT_DEF (obj))
     {
-      struct ipa_jump_func jfunc;
       if (TREE_CODE (SSA_NAME_VAR (obj)) != PARM_DECL)
        return;
 
       anc_offset = 0;
       index = ipa_get_param_decl_index (info, SSA_NAME_VAR (obj));
       gcc_assert (index >= 0);
-      if (detect_type_change_ssa (obj, obj_type_ref_class (target),
-                                 call, &jfunc))
+      if (detect_type_change_ssa (fbi, obj, obj_type_ref_class (target),
+                                 call))
        return;
     }
   else
     {
-      struct ipa_jump_func jfunc;
       gimple *stmt = SSA_NAME_DEF_STMT (obj);
       tree expr;
 
@@ -2229,13 +2629,14 @@ ipa_analyze_virtual_call_uses (struct ipa_func_body_info *fbi,
       index = ipa_get_param_decl_index (info,
                                        SSA_NAME_VAR (TREE_OPERAND (expr, 0)));
       gcc_assert (index >= 0);
-      if (detect_type_change (obj, expr, obj_type_ref_class (target),
-                             call, &jfunc, anc_offset))
+      if (detect_type_change (fbi, obj, expr, obj_type_ref_class (target),
+                             call, anc_offset))
        return;
     }
 
-  struct cgraph_edge *cs = ipa_note_param_call (fbi->node, index, call);
-  struct cgraph_indirect_call_info *ii = cs->indirect_info;
+  struct cgraph_edge *cs = ipa_note_param_call (fbi->node, index,
+                                               call, true);
+  class cgraph_indirect_call_info *ii = cs->indirect_info;
   ii->offset = anc_offset;
   ii->otr_token = tree_to_uhwi (OBJ_TYPE_REF_TOKEN (target));
   ii->otr_type = obj_type_ref_class (target);
@@ -2277,7 +2678,8 @@ ipa_analyze_call_uses (struct ipa_func_body_info *fbi, gcall *call)
       cs->indirect_info->vptr_changed
        = !context.get_dynamic_type (instance,
                                     OBJ_TYPE_REF_OBJECT (target),
-                                    obj_type_ref_class (target), call);
+                                    obj_type_ref_class (target), call,
+                                    &fbi->aa_walk_budget);
       cs->indirect_info->context = context;
     }
 
@@ -2306,7 +2708,7 @@ ipa_analyze_stmt_uses (struct ipa_func_body_info *fbi, gimple *stmt)
 static bool
 visit_ref_for_mod_analysis (gimple *, tree op, tree, void *data)
 {
-  struct ipa_node_params *info = (struct ipa_node_params *) data;
+  class ipa_node_params *info = (class ipa_node_params *) data;
 
   op = get_base_address (op);
   if (op
@@ -2354,7 +2756,7 @@ ipa_analyze_params_uses_in_bb (struct ipa_func_body_info *fbi, basic_block bb)
 static void
 ipa_analyze_controlled_uses (struct cgraph_node *node)
 {
-  struct ipa_node_params *info = IPA_NODE_REF (node);
+  class ipa_node_params *info = IPA_NODE_REF (node);
 
   for (int i = 0; i < ipa_get_param_count (info); i++)
     {
@@ -2446,11 +2848,11 @@ void
 ipa_analyze_node (struct cgraph_node *node)
 {
   struct ipa_func_body_info fbi;
-  struct ipa_node_params *info;
+  class ipa_node_params *info;
 
   ipa_check_create_node_params ();
   ipa_check_create_edge_args ();
-  info = IPA_NODE_REF (node);
+  info = IPA_NODE_REF_GET_CREATE (node);
 
   if (info->analysis_done)
     return;
@@ -2477,7 +2879,7 @@ ipa_analyze_node (struct cgraph_node *node)
   fbi.bb_infos = vNULL;
   fbi.bb_infos.safe_grow_cleared (last_basic_block_for_fn (cfun));
   fbi.param_count = ipa_get_param_count (info);
-  fbi.aa_walked = 0;
+  fbi.aa_walk_budget = opt_for_fn (node->decl, param_ipa_max_aa_steps);
 
   for (struct cgraph_edge *cs = node->callees; cs; cs = cs->next_callee)
     {
@@ -2506,22 +2908,96 @@ static void
 update_jump_functions_after_inlining (struct cgraph_edge *cs,
                                      struct cgraph_edge *e)
 {
-  struct ipa_edge_args *top = IPA_EDGE_REF (cs);
-  struct ipa_edge_args *args = IPA_EDGE_REF (e);
+  class ipa_edge_args *top = IPA_EDGE_REF (cs);
+  class ipa_edge_args *args = IPA_EDGE_REF (e);
+  if (!args)
+    return;
   int count = ipa_get_cs_argument_count (args);
   int i;
 
   for (i = 0; i < count; i++)
     {
       struct ipa_jump_func *dst = ipa_get_ith_jump_func (args, i);
-      struct ipa_polymorphic_call_context *dst_ctx
+      class ipa_polymorphic_call_context *dst_ctx
        = ipa_get_ith_polymorhic_call_context (args, i);
 
+      if (dst->agg.items)
+       {
+         struct ipa_agg_jf_item *item;
+         int j;
+
+         FOR_EACH_VEC_ELT (*dst->agg.items, j, item)
+           {
+             int dst_fid;
+             struct ipa_jump_func *src;
+
+             if (item->jftype != IPA_JF_PASS_THROUGH
+                 && item->jftype != IPA_JF_LOAD_AGG)
+               continue;
+
+             dst_fid = item->value.pass_through.formal_id;
+             if (!top || dst_fid >= ipa_get_cs_argument_count (top))
+               {
+                 item->jftype = IPA_JF_UNKNOWN;
+                 continue;
+               }
+
+             item->value.pass_through.formal_id = -1;
+             src = ipa_get_ith_jump_func (top, dst_fid);
+             if (src->type == IPA_JF_CONST)
+               {
+                 if (item->jftype == IPA_JF_PASS_THROUGH
+                     && item->value.pass_through.operation == NOP_EXPR)
+                   {
+                     item->jftype = IPA_JF_CONST;
+                     item->value.constant = src->value.constant.value;
+                     continue;
+                   }
+               }
+             else if (src->type == IPA_JF_PASS_THROUGH
+                      && src->value.pass_through.operation == NOP_EXPR)
+               {
+                 if (item->jftype == IPA_JF_PASS_THROUGH
+                     || !item->value.load_agg.by_ref
+                     || src->value.pass_through.agg_preserved)
+                   item->value.pass_through.formal_id
+                               = src->value.pass_through.formal_id;
+               }
+             else if (src->type == IPA_JF_ANCESTOR)
+               {
+                 if (item->jftype == IPA_JF_PASS_THROUGH)
+                   {
+                     if (!src->value.ancestor.offset)
+                       item->value.pass_through.formal_id
+                               = src->value.ancestor.formal_id;
+                   }
+                 else if (src->value.ancestor.agg_preserved)
+                   {
+                     gcc_checking_assert (item->value.load_agg.by_ref);
+
+                     item->value.pass_through.formal_id
+                                = src->value.ancestor.formal_id;
+                     item->value.load_agg.offset
+                               += src->value.ancestor.offset;
+                   }
+               }
+
+             if (item->value.pass_through.formal_id < 0)
+               item->jftype = IPA_JF_UNKNOWN;
+           }
+       }
+
+      if (!top)
+       {
+         ipa_set_jf_unknown (dst);
+         continue;
+       }
+
       if (dst->type == IPA_JF_ANCESTOR)
        {
          struct ipa_jump_func *src;
          int dst_fid = dst->value.ancestor.formal_id;
-         struct ipa_polymorphic_call_context *src_ctx
+         class ipa_polymorphic_call_context *src_ctx
            = ipa_get_ith_polymorhic_call_context (top, dst_fid);
 
          /* Variable number of arguments can cause havoc if we try to access
@@ -2537,7 +3013,7 @@ update_jump_functions_after_inlining (struct cgraph_edge *cs,
 
          if (src_ctx && !src_ctx->useless_p ())
            {
-             struct ipa_polymorphic_call_context ctx = *src_ctx;
+             class ipa_polymorphic_call_context ctx = *src_ctx;
 
              /* TODO: Make type preserved safe WRT contexts.  */
              if (!ipa_get_jf_ancestor_type_preserved (dst))
@@ -2556,8 +3032,11 @@ update_jump_functions_after_inlining (struct cgraph_edge *cs,
                }
            }
 
-         if (src->agg.items
-             && (dst->value.ancestor.agg_preserved || !src->agg.by_ref))
+         /* Parameter and argument in ancestor jump function must be pointer
+            type, which means access to aggregate must be by-reference.  */
+         gcc_assert (!src->agg.items || src->agg.by_ref);
+
+         if (src->agg.items && dst->value.ancestor.agg_preserved)
            {
              struct ipa_agg_jf_item *item;
              int j;
@@ -2579,12 +3058,6 @@ update_jump_functions_after_inlining (struct cgraph_edge *cs,
              dst->value.ancestor.agg_preserved &=
                src->value.pass_through.agg_preserved;
            }
-         else if (src->type == IPA_JF_PASS_THROUGH
-                  && TREE_CODE_CLASS (src->value.pass_through.operation) == tcc_unary)
-           {
-             dst->value.ancestor.formal_id = src->value.pass_through.formal_id;
-             dst->value.ancestor.agg_preserved = false;
-           }
          else if (src->type == IPA_JF_ANCESTOR)
            {
              dst->value.ancestor.formal_id = src->value.ancestor.formal_id;
@@ -2601,18 +3074,18 @@ update_jump_functions_after_inlining (struct cgraph_edge *cs,
          /* We must check range due to calls with variable number of arguments
             and we cannot combine jump functions with operations.  */
          if (dst->value.pass_through.operation == NOP_EXPR
-             && (dst->value.pass_through.formal_id
+             && (top && dst->value.pass_through.formal_id
                  < ipa_get_cs_argument_count (top)))
            {
              int dst_fid = dst->value.pass_through.formal_id;
              src = ipa_get_ith_jump_func (top, dst_fid);
              bool dst_agg_p = ipa_get_jf_pass_through_agg_preserved (dst);
-             struct ipa_polymorphic_call_context *src_ctx
+             class ipa_polymorphic_call_context *src_ctx
                = ipa_get_ith_polymorhic_call_context (top, dst_fid);
 
              if (src_ctx && !src_ctx->useless_p ())
                {
-                 struct ipa_polymorphic_call_context ctx = *src_ctx;
+                 class ipa_polymorphic_call_context ctx = *src_ctx;
 
                  /* TODO: Make type preserved safe WRT contexts.  */
                  if (!ipa_get_jf_pass_through_type_preserved (dst))
@@ -2701,7 +3174,6 @@ ipa_make_edge_direct_to_target (struct cgraph_edge *ie, tree target,
                                bool speculative)
 {
   struct cgraph_node *callee;
-  struct inline_edge_summary *es = inline_edge_summary (ie);
   bool unreachable = false;
 
   if (TREE_CODE (target) == ADDR_EXPR)
@@ -2725,11 +3197,9 @@ ipa_make_edge_direct_to_target (struct cgraph_edge *ie, tree target,
            {
              if (dump_enabled_p ())
                {
-                 location_t loc = gimple_location_safe (ie->call_stmt);
-                 dump_printf_loc (MSG_OPTIMIZED_LOCATIONS, loc,
-                                  "discovered direct call non-invariant "
-                                  "%s/%i\n",
-                                  ie->caller->name (), ie->caller->order);
+                 dump_printf_loc (MSG_OPTIMIZED_LOCATIONS, ie->call_stmt,
+                                  "discovered direct call non-invariant %s\n",
+                                  ie->caller->dump_name ());
                }
              return NULL;
            }
@@ -2737,11 +3207,10 @@ ipa_make_edge_direct_to_target (struct cgraph_edge *ie, tree target,
 
           if (dump_enabled_p ())
            {
-             location_t loc = gimple_location_safe (ie->call_stmt);
-             dump_printf_loc (MSG_OPTIMIZED_LOCATIONS, loc,
-                              "discovered direct call to non-function in %s/%i, "
+             dump_printf_loc (MSG_OPTIMIZED_LOCATIONS, ie->call_stmt,
+                              "discovered direct call to non-function in %s, "
                               "making it __builtin_unreachable\n",
-                              ie->caller->name (), ie->caller->order);
+                              ie->caller->dump_name ());
            }
 
          target = builtin_decl_implicit (BUILT_IN_UNREACHABLE);
@@ -2756,7 +3225,7 @@ ipa_make_edge_direct_to_target (struct cgraph_edge *ie, tree target,
 
   /* Because may-edges are not explicitely represented and vtable may be external,
      we may create the first reference to the object in the unit.  */
-  if (!callee || callee->global.inlined_to)
+  if (!callee || callee->inlined_to)
     {
 
       /* We are better to ensure we can refer to it.
@@ -2768,11 +3237,9 @@ ipa_make_edge_direct_to_target (struct cgraph_edge *ie, tree target,
        {
          if (dump_file)
            fprintf (dump_file, "ipa-prop: Discovered call to a known target "
-                    "(%s/%i -> %s/%i) but can not refer to it. Giving up.\n",
-                    xstrdup_for_dump (ie->caller->name ()),
-                    ie->caller->order,
-                    xstrdup_for_dump (ie->callee->name ()),
-                    ie->callee->order);
+                    "(%s -> %s) but cannot refer to it. Giving up.\n",
+                    ie->caller->dump_name (),
+                    ie->callee->dump_name ());
          return NULL;
        }
       callee = cgraph_node::get_create (target);
@@ -2788,24 +3255,18 @@ ipa_make_edge_direct_to_target (struct cgraph_edge *ie, tree target,
          != callee->ultimate_alias_target ())
        {
          if (dump_file)
-           fprintf (dump_file, "ipa-prop: Discovered call to a speculative target "
-                    "(%s/%i -> %s/%i) but the call is already speculated to %s/%i. Giving up.\n",
-                    xstrdup_for_dump (ie->caller->name ()),
-                    ie->caller->order,
-                    xstrdup_for_dump (callee->name ()),
-                    callee->order,
-                    xstrdup_for_dump (e2->callee->name ()),
-                    e2->callee->order);
+           fprintf (dump_file, "ipa-prop: Discovered call to a speculative "
+                    "target (%s -> %s) but the call is already "
+                    "speculated to %s. Giving up.\n",
+                    ie->caller->dump_name (), callee->dump_name (),
+                    e2->callee->dump_name ());
        }
       else
        {
          if (dump_file)
            fprintf (dump_file, "ipa-prop: Discovered call to a speculative target "
-                    "(%s/%i -> %s/%i) this agree with previous speculation.\n",
-                    xstrdup_for_dump (ie->caller->name ()),
-                    ie->caller->order,
-                    xstrdup_for_dump (callee->name ()),
-                    callee->order);
+                    "(%s -> %s) this agree with previous speculation.\n",
+                    ie->caller->dump_name (), callee->dump_name ());
        }
       return NULL;
     }
@@ -2815,20 +3276,18 @@ ipa_make_edge_direct_to_target (struct cgraph_edge *ie, tree target,
 
   ipa_check_create_node_params ();
 
-  /* We can not make edges to inline clones.  It is bug that someone removed
+  /* We cannot make edges to inline clones.  It is bug that someone removed
      the cgraph node too early.  */
-  gcc_assert (!callee->global.inlined_to);
+  gcc_assert (!callee->inlined_to);
 
   if (dump_file && !unreachable)
     {
       fprintf (dump_file, "ipa-prop: Discovered %s call to a %s target "
-              "(%s/%i -> %s/%i), for stmt ",
+              "(%s -> %s), for stmt ",
               ie->indirect_info->polymorphic ? "a virtual" : "an indirect",
               speculative ? "speculative" : "known",
-              xstrdup_for_dump (ie->caller->name ()),
-              ie->caller->order,
-              xstrdup_for_dump (callee->name ()),
-              callee->order);
+              ie->caller->dump_name (),
+              callee->dump_name ());
       if (ie->call_stmt)
        print_gimple_stmt (dump_file, ie->call_stmt, 2, TDF_SLIM);
       else
@@ -2836,21 +3295,19 @@ ipa_make_edge_direct_to_target (struct cgraph_edge *ie, tree target,
      }
   if (dump_enabled_p ())
     {
-      location_t loc = gimple_location_safe (ie->call_stmt);
-
-      dump_printf_loc (MSG_OPTIMIZED_LOCATIONS, loc,
+      dump_printf_loc (MSG_OPTIMIZED_LOCATIONS, ie->call_stmt,
                       "converting indirect call in %s to direct call to %s\n",
-                      ie->caller->name (), callee->name ());
+                      ie->caller->dump_name (), callee->dump_name ());
     }
   if (!speculative)
     {
       struct cgraph_edge *orig = ie;
-      ie = ie->make_direct (callee);
+      ie = cgraph_edge::make_direct (ie, callee);
       /* If we resolved speculative edge the cost is already up to date
         for direct call (adjusted by inline_edge_duplication_hook).  */
       if (ie == orig)
        {
-         es = inline_edge_summary (ie);
+         ipa_call_summary *es = ipa_call_summaries->get (ie);
          es->call_stmt_size -= (eni_size_weights.indirect_call_cost
                                 - eni_size_weights.call_cost);
          es->call_stmt_time -= (eni_time_weights.indirect_call_cost
@@ -2868,7 +3325,7 @@ ipa_make_edge_direct_to_target (struct cgraph_edge *ie, tree target,
        }
       /* make_speculative will update ie's cost to direct call cost. */
       ie = ie->make_speculative
-            (callee, ie->count * 8 / 10, ie->frequency * 8 / 10);
+            (callee, ie->count.apply_scale (8, 10));
     }
 
   return ie;
@@ -2899,7 +3356,10 @@ find_constructor_constant_at_offset (tree constructor, HOST_WIDE_INT req_offset)
 
          if (index)
            {
-             off = wi::to_offset (index);
+            if (TREE_CODE (index) == RANGE_EXPR)
+              off = wi::to_offset (TREE_OPERAND (index, 0));
+            else
+              off = wi::to_offset (index);
              if (TYPE_DOMAIN (type) && TYPE_MIN_VALUE (TYPE_DOMAIN (type)))
                {
                  tree low_bound = TYPE_MIN_VALUE (TYPE_DOMAIN (type));
@@ -2908,6 +3368,8 @@ find_constructor_constant_at_offset (tree constructor, HOST_WIDE_INT req_offset)
                                  TYPE_PRECISION (TREE_TYPE (index)));
                }
              off *= wi::to_offset (unit_size);
+            /* ???  Handle more than just the first index of a
+               RANGE_EXPR.  */
            }
          else
            off = wi::to_offset (unit_size) * ix;
@@ -2966,18 +3428,19 @@ ipa_find_agg_cst_from_init (tree scalar, HOST_WIDE_INT offset, bool by_ref)
   return find_constructor_constant_at_offset (DECL_INITIAL (scalar), offset);
 }
 
-/* Retrieve value from aggregate jump function AGG or static initializer of
-   SCALAR (which can be NULL) for the given OFFSET or return NULL if there is
-   none.  BY_REF specifies whether the value has to be passed by reference or
-   by value.  If FROM_GLOBAL_CONSTANT is non-NULL, then the boolean it points
-   to is set to true if the value comes from an initializer of a constant.  */
+/* Retrieve value from AGG, a set of known offset/value for an aggregate or
+   static initializer of SCALAR (which can be NULL) for the given OFFSET or
+   return NULL if there is none.  BY_REF specifies whether the value has to be
+   passed by reference or by value.  If FROM_GLOBAL_CONSTANT is non-NULL, then
+   the boolean it points to is set to true if the value comes from an
+   initializer of a constant.  */
 
 tree
-ipa_find_agg_cst_for_param (struct ipa_agg_jump_function *agg, tree scalar,
+ipa_find_agg_cst_for_param (struct ipa_agg_value_set *agg, tree scalar,
                            HOST_WIDE_INT offset, bool by_ref,
                            bool *from_global_constant)
 {
-  struct ipa_agg_jf_item *item;
+  struct ipa_agg_value *item;
   int i;
 
   if (scalar)
@@ -2995,7 +3458,7 @@ ipa_find_agg_cst_for_param (struct ipa_agg_jump_function *agg, tree scalar,
       || by_ref != agg->by_ref)
     return NULL;
 
-  FOR_EACH_VEC_SAFE_ELT (agg->items, i, item)
+  FOR_EACH_VEC_ELT (agg->items, i, item)
     if (item->offset == offset)
       {
        /* Currently we do not have clobber values, return NULL for them once
@@ -3028,9 +3491,8 @@ remove_described_reference (symtab_node *symbol, struct ipa_cst_ref_desc *rdesc)
 
   to_del->remove_reference ();
   if (dump_file)
-    fprintf (dump_file, "ipa-prop: Removed a reference from %s/%i to %s.\n",
-            xstrdup_for_dump (origin->caller->name ()),
-            origin->caller->order, xstrdup_for_dump (symbol->name ()));
+    fprintf (dump_file, "ipa-prop: Removed a reference from %s to %s.\n",
+            origin->caller->dump_name (), symbol->dump_name ());
   return true;
 }
 
@@ -3089,26 +3551,33 @@ try_decrement_rdesc_refcount (struct ipa_jump_func *jfunc)
 
 /* Try to find a destination for indirect edge IE that corresponds to a simple
    call or a call of a member function pointer and where the destination is a
-   pointer formal parameter described by jump function JFUNC.  If it can be
-   determined, return the newly direct edge, otherwise return NULL.
-   NEW_ROOT_INFO is the node info that JFUNC lattices are relative to.  */
+   pointer formal parameter described by jump function JFUNC.  TARGET_TYPE is
+   the type of the parameter to which the result of JFUNC is passed.  If it can
+   be determined, return the newly direct edge, otherwise return NULL.
+   NEW_ROOT and NEW_ROOT_INFO is the node and its info that JFUNC lattices are
+   relative to.  */
 
 static struct cgraph_edge *
 try_make_edge_direct_simple_call (struct cgraph_edge *ie,
-                                 struct ipa_jump_func *jfunc,
-                                 struct ipa_node_params *new_root_info)
+                                 struct ipa_jump_func *jfunc, tree target_type,
+                                 struct cgraph_node *new_root,
+                                 class ipa_node_params *new_root_info)
 {
   struct cgraph_edge *cs;
   tree target;
   bool agg_contents = ie->indirect_info->agg_contents;
-  tree scalar = ipa_value_from_jfunc (new_root_info, jfunc);
+  tree scalar = ipa_value_from_jfunc (new_root_info, jfunc, target_type);
   if (agg_contents)
     {
       bool from_global_constant;
-      target = ipa_find_agg_cst_for_param (&jfunc->agg, scalar,
+      ipa_agg_value_set agg = ipa_agg_value_set_from_jfunc (new_root_info,
+                                                           new_root,
+                                                           &jfunc->agg);
+      target = ipa_find_agg_cst_for_param (&agg, scalar,
                                           ie->indirect_info->offset,
                                           ie->indirect_info->by_ref,
                                           &from_global_constant);
+      agg.release ();
       if (target
          && !from_global_constant
          && !ie->indirect_info->guaranteed_unmodified)
@@ -3145,13 +3614,13 @@ ipa_impossible_devirt_target (struct cgraph_edge *ie, tree target)
     {
       if (target)
        fprintf (dump_file,
-                "Type inconsistent devirtualization: %s/%i->%s\n",
-                ie->caller->name (), ie->caller->order,
+                "Type inconsistent devirtualization: %s->%s\n",
+                ie->caller->dump_name (),
                 IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (target)));
       else
        fprintf (dump_file,
-                "No devirtualization target in %s/%i\n",
-                ie->caller->name (), ie->caller->order);
+                "No devirtualization target in %s\n",
+                ie->caller->dump_name ());
     }
   tree new_target = builtin_decl_implicit (BUILT_IN_UNREACHABLE);
   cgraph_node::get_create (new_target);
@@ -3162,12 +3631,16 @@ ipa_impossible_devirt_target (struct cgraph_edge *ie, tree target)
    call based on a formal parameter which is described by jump function JFUNC
    and if it can be determined, make it direct and return the direct edge.
    Otherwise, return NULL.  CTX describes the polymorphic context that the
-   parameter the call is based on brings along with it.  */
+   parameter the call is based on brings along with it.  NEW_ROOT and
+   NEW_ROOT_INFO is the node and its info that JFUNC lattices are relative
+   to.  */
 
 static struct cgraph_edge *
 try_make_edge_direct_virtual_call (struct cgraph_edge *ie,
                                   struct ipa_jump_func *jfunc,
-                                  struct ipa_polymorphic_call_context ctx)
+                                  class ipa_polymorphic_call_context ctx,
+                                  struct cgraph_node *new_root,
+                                  class ipa_node_params *new_root_info)
 {
   tree target = NULL;
   bool speculative = false;
@@ -3185,9 +3658,13 @@ try_make_edge_direct_virtual_call (struct cgraph_edge *ie,
       unsigned HOST_WIDE_INT offset;
       tree scalar = (jfunc->type == IPA_JF_CONST) ? ipa_get_jf_constant (jfunc)
        : NULL;
-      tree t = ipa_find_agg_cst_for_param (&jfunc->agg, scalar,
+      ipa_agg_value_set agg = ipa_agg_value_set_from_jfunc (new_root_info,
+                                                           new_root,
+                                                           &jfunc->agg);
+      tree t = ipa_find_agg_cst_for_param (&agg, scalar,
                                           ie->indirect_info->offset,
                                           true);
+      agg.release ();
       if (t && vtable_pointer_value_to_vtable (t, &vtable, &offset))
        {
          bool can_refer;
@@ -3196,8 +3673,7 @@ try_make_edge_direct_virtual_call (struct cgraph_edge *ie,
          if (can_refer)
            {
              if (!t
-                 || (TREE_CODE (TREE_TYPE (t)) == FUNCTION_TYPE
-                     && DECL_FUNCTION_CODE (t) == BUILT_IN_UNREACHABLE)
+                 || fndecl_built_in_p (t, BUILT_IN_UNREACHABLE)
                  || !possible_polymorphic_call_target_p
                       (ie, cgraph_node::get (t)))
                {
@@ -3277,20 +3753,22 @@ update_indirect_edges_after_inlining (struct cgraph_edge *cs,
                                      struct cgraph_node *node,
                                      vec<cgraph_edge *> *new_edges)
 {
-  struct ipa_edge_args *top;
+  class ipa_edge_args *top;
   struct cgraph_edge *ie, *next_ie, *new_direct_edge;
-  struct ipa_node_params *new_root_info;
+  struct cgraph_node *new_root;
+  class ipa_node_params *new_root_info, *inlined_node_info;
   bool res = false;
 
   ipa_check_create_edge_args ();
   top = IPA_EDGE_REF (cs);
-  new_root_info = IPA_NODE_REF (cs->caller->global.inlined_to
-                               ? cs->caller->global.inlined_to
-                               : cs->caller);
+  new_root = cs->caller->inlined_to
+               ? cs->caller->inlined_to : cs->caller;
+  new_root_info = IPA_NODE_REF (new_root);
+  inlined_node_info = IPA_NODE_REF (cs->callee->function_symbol ());
 
   for (ie = node->indirect_calls; ie; ie = next_ie)
     {
-      struct cgraph_indirect_call_info *ici = ie->indirect_info;
+      class cgraph_indirect_call_info *ici = ie->indirect_info;
       struct ipa_jump_func *jfunc;
       int param_index;
       cgraph_node *spec_target = NULL;
@@ -3301,7 +3779,7 @@ update_indirect_edges_after_inlining (struct cgraph_edge *cs,
        continue;
 
       /* We must check range due to calls with variable number of arguments:  */
-      if (ici->param_index >= ipa_get_cs_argument_count (top))
+      if (!top || ici->param_index >= ipa_get_cs_argument_count (top))
        {
          ici->param_index = -1;
          continue;
@@ -3324,11 +3802,19 @@ update_indirect_edges_after_inlining (struct cgraph_edge *cs,
        {
           ipa_polymorphic_call_context ctx;
          ctx = ipa_context_from_jfunc (new_root_info, cs, param_index, jfunc);
-         new_direct_edge = try_make_edge_direct_virtual_call (ie, jfunc, ctx);
+         new_direct_edge = try_make_edge_direct_virtual_call (ie, jfunc, ctx,
+                                                              new_root,
+                                                              new_root_info);
        }
       else
-       new_direct_edge = try_make_edge_direct_simple_call (ie, jfunc,
-                                                           new_root_info);
+       {
+         tree target_type =  ipa_get_type (inlined_node_info, param_index);
+         new_direct_edge = try_make_edge_direct_simple_call (ie, jfunc,
+                                                             target_type,
+                                                             new_root,
+                                                             new_root_info);
+       }
+
       /* If speculation was removed, then we need to do nothing.  */
       if (new_direct_edge && new_direct_edge != ie
          && new_direct_edge->callee == spec_target)
@@ -3342,11 +3828,6 @@ update_indirect_edges_after_inlining (struct cgraph_edge *cs,
       else if (new_direct_edge)
        {
          new_direct_edge->indirect_inlining_edge = 1;
-         if (new_direct_edge->call_stmt)
-           new_direct_edge->call_stmt_cannot_inline_p
-             = !gimple_check_call_matching_types (
-                 new_direct_edge->call_stmt,
-                 new_direct_edge->callee->decl, false);
          if (new_edges)
            {
              new_edges->safe_push (new_direct_edge);
@@ -3371,6 +3852,11 @@ update_indirect_edges_after_inlining (struct cgraph_edge *cs,
              if (ici->polymorphic
                  && !ipa_get_jf_pass_through_type_preserved (jfunc))
                ici->vptr_changed = true;
+             ipa_set_param_used_by_indirect_call (new_root_info,
+                                                  ici->param_index, true);
+             if (ici->polymorphic)
+               ipa_set_param_used_by_polymorphic_call (new_root_info,
+                                                       ici->param_index, true);
            }
        }
       else if (jfunc->type == IPA_JF_ANCESTOR)
@@ -3386,6 +3872,11 @@ update_indirect_edges_after_inlining (struct cgraph_edge *cs,
              if (ici->polymorphic
                  && !ipa_get_jf_ancestor_type_preserved (jfunc))
                ici->vptr_changed = true;
+             ipa_set_param_used_by_indirect_call (new_root_info,
+                                                  ici->param_index, true);
+             if (ici->polymorphic)
+               ipa_set_param_used_by_polymorphic_call (new_root_info,
+                                                       ici->param_index, true);
            }
        }
       else
@@ -3442,13 +3933,18 @@ combine_controlled_uses_counters (int c, int d)
 static void
 propagate_controlled_uses (struct cgraph_edge *cs)
 {
-  struct ipa_edge_args *args = IPA_EDGE_REF (cs);
-  struct cgraph_node *new_root = cs->caller->global.inlined_to
-    ? cs->caller->global.inlined_to : cs->caller;
-  struct ipa_node_params *new_root_info = IPA_NODE_REF (new_root);
-  struct ipa_node_params *old_root_info = IPA_NODE_REF (cs->callee);
+  class ipa_edge_args *args = IPA_EDGE_REF (cs);
+  if (!args)
+    return;
+  struct cgraph_node *new_root = cs->caller->inlined_to
+    ? cs->caller->inlined_to : cs->caller;
+  class ipa_node_params *new_root_info = IPA_NODE_REF (new_root);
+  class ipa_node_params *old_root_info = IPA_NODE_REF (cs->callee);
   int count, i;
 
+  if (!old_root_info)
+    return;
+
   count = MIN (ipa_get_cs_argument_count (args),
               ipa_get_param_count (old_root_info));
   for (i = 0; i < count; i++)
@@ -3480,10 +3976,9 @@ propagate_controlled_uses (struct cgraph_edge *cs)
                {
                  if (dump_file)
                    fprintf (dump_file, "ipa-prop: Removing cloning-created "
-                            "reference from %s/%i to %s/%i.\n",
-                            xstrdup_for_dump (new_root->name ()),
-                            new_root->order,
-                            xstrdup_for_dump (n->name ()), n->order);
+                            "reference from %s to %s.\n",
+                            new_root->dump_name (),
+                            n->dump_name ());
                  ref->remove_reference ();
                }
            }
@@ -3510,9 +4005,9 @@ propagate_controlled_uses (struct cgraph_edge *cs)
                  gcc_checking_assert (ok);
 
                  clone = cs->caller;
-                 while (clone->global.inlined_to
-                        && clone != rdesc->cs->caller
-                        && IPA_NODE_REF (clone)->ipcp_orig_node)
+                 while (clone->inlined_to
+                        && clone->ipcp_clone
+                        && clone != rdesc->cs->caller)
                    {
                      struct ipa_ref *ref;
                      ref = clone->find_reference (n, NULL, 0);
@@ -3521,11 +4016,9 @@ propagate_controlled_uses (struct cgraph_edge *cs)
                          if (dump_file)
                            fprintf (dump_file, "ipa-prop: Removing "
                                     "cloning-created reference "
-                                    "from %s/%i to %s/%i.\n",
-                                    xstrdup_for_dump (clone->name ()),
-                                    clone->order,
-                                    xstrdup_for_dump (n->name ()),
-                                    n->order);
+                                    "from %s to %s.\n",
+                                    clone->dump_name (),
+                                    n->dump_name ());
                          ref->remove_reference ();
                        }
                      clone = clone->callers->caller;
@@ -3569,22 +4062,52 @@ ipa_propagate_indirect_call_infos (struct cgraph_edge *cs,
      (i.e. during early inlining).  */
   if (!ipa_node_params_sum)
     return false;
-  gcc_assert (ipa_edge_args_vector);
+  gcc_assert (ipa_edge_args_sum);
 
   propagate_controlled_uses (cs);
   changed = propagate_info_to_inlined_callees (cs, cs->callee, new_edges);
+  ipa_node_params_sum->remove (cs->callee);
+
+  class ipa_edge_args *args = IPA_EDGE_REF (cs);
+  if (args)
+    {
+      bool ok = true;
+      if (args->jump_functions)
+       {
+         struct ipa_jump_func *jf;
+         int i;
+         FOR_EACH_VEC_ELT (*args->jump_functions, i, jf)
+           if (jf->type == IPA_JF_CONST
+               && ipa_get_jf_constant_rdesc (jf))
+             {
+               ok = false;
+               break;
+             }
+       }
+      if (ok)
+        ipa_edge_args_sum->remove (cs);
+    }
+  if (ipcp_transformation_sum)
+    ipcp_transformation_sum->remove (cs->callee);
 
   return changed;
 }
 
-/* Frees all dynamically allocated structures that the argument info points
-   to.  */
+/* Ensure that array of edge arguments infos is big enough to accommodate a
+   structure for all edges and reallocates it if not.  Also, allocate
+   associated hash tables is they do not already exist.  */
 
 void
-ipa_free_edge_args_substructures (struct ipa_edge_args *args)
-{
-  vec_free (args->jump_functions);
-  memset (args, 0, sizeof (*args));
+ipa_check_create_edge_args (void)
+{
+  if (!ipa_edge_args_sum)
+    ipa_edge_args_sum
+      = (new (ggc_alloc_no_dtor<ipa_edge_args_sum_t> ())
+        ipa_edge_args_sum_t (symtab, true));
+  if (!ipa_bits_hash_table)
+    ipa_bits_hash_table = hash_table<ipa_bit_ggc_hash_traits>::create_ggc (37);
+  if (!ipa_vr_hash_table)
+    ipa_vr_hash_table = hash_table<ipa_vr_ggc_hash_traits>::create_ggc (37);
 }
 
 /* Free all ipa_edge structures.  */
@@ -3592,37 +4115,11 @@ ipa_free_edge_args_substructures (struct ipa_edge_args *args)
 void
 ipa_free_all_edge_args (void)
 {
-  int i;
-  struct ipa_edge_args *args;
-
-  if (!ipa_edge_args_vector)
+  if (!ipa_edge_args_sum)
     return;
 
-  FOR_EACH_VEC_ELT (*ipa_edge_args_vector, i, args)
-    ipa_free_edge_args_substructures (args);
-
-  vec_free (ipa_edge_args_vector);
-}
-
-/* Frees all dynamically allocated structures that the param info points
-   to.  */
-
-ipa_node_params::~ipa_node_params ()
-{
-  descriptors.release ();
-  free (lattices);
-  /* Lattice values and their sources are deallocated with their alocation
-     pool.  */
-  known_csts.release ();
-  known_contexts.release ();
-
-  lattices = NULL;
-  ipcp_orig_node = NULL;
-  analysis_done = 0;
-  node_enqueued = 0;
-  do_clone_for_all_contexts = 0;
-  is_all_contexts_clone = 0;
-  node_dead = 0;
+  ggc_delete (ipa_edge_args_sum);
+  ipa_edge_args_sum = NULL;
 }
 
 /* Free all ipa_node_params structures.  */
@@ -3630,18 +4127,35 @@ ipa_node_params::~ipa_node_params ()
 void
 ipa_free_all_node_params (void)
 {
-  delete ipa_node_params_sum;
+  ggc_delete (ipa_node_params_sum);
   ipa_node_params_sum = NULL;
 }
 
-/* Grow ipcp_transformations if necessary.  */
+/* Initialize IPA CP transformation summary and also allocate any necessary hash
+   tables if they do not already exist.  */
+
+void
+ipcp_transformation_initialize (void)
+{
+  if (!ipa_bits_hash_table)
+    ipa_bits_hash_table = hash_table<ipa_bit_ggc_hash_traits>::create_ggc (37);
+  if (!ipa_vr_hash_table)
+    ipa_vr_hash_table = hash_table<ipa_vr_ggc_hash_traits>::create_ggc (37);
+  if (ipcp_transformation_sum == NULL)
+    ipcp_transformation_sum = ipcp_transformation_t::create_ggc (symtab);
+}
+
+/* Release the IPA CP transformation summary.  */
 
 void
-ipcp_grow_transformations_if_necessary (void)
+ipcp_free_transformation_sum (void)
 {
-  if (vec_safe_length (ipcp_transformations)
-      <= (unsigned) symtab->cgraph_max_uid)
-    vec_safe_grow_cleared (ipcp_transformations, symtab->cgraph_max_uid + 1);
+  if (!ipcp_transformation_sum)
+    return;
+
+  ipcp_transformation_sum->~function_summary<ipcp_transformation *> ();
+  ggc_free (ipcp_transformation_sum);
+  ipcp_transformation_sum = NULL;
 }
 
 /* Set the aggregate replacements of NODE to be AGGVALS.  */
@@ -3650,22 +4164,17 @@ void
 ipa_set_node_agg_value_chain (struct cgraph_node *node,
                              struct ipa_agg_replacement_value *aggvals)
 {
-  ipcp_grow_transformations_if_necessary ();
-  (*ipcp_transformations)[node->uid].agg_values = aggvals;
+  ipcp_transformation_initialize ();
+  ipcp_transformation *s = ipcp_transformation_sum->get_create (node);
+  s->agg_values = aggvals;
 }
 
-/* Hook that is called by cgraph.c when an edge is removed.  */
+/* Hook that is called by cgraph.c when an edge is removed.  Adjust reference
+   count data structures accordingly.  */
 
-static void
-ipa_edge_removal_hook (struct cgraph_edge *cs, void *data ATTRIBUTE_UNUSED)
+void
+ipa_edge_args_sum_t::remove (cgraph_edge *cs, ipa_edge_args *args)
 {
-  struct ipa_edge_args *args;
-
-  /* During IPA-CP updating we can be called on not-yet analyzed clones.  */
-  if (vec_safe_length (ipa_edge_args_vector) <= (unsigned)cs->uid)
-    return;
-
-  args = IPA_EDGE_REF (cs);
   if (args->jump_functions)
     {
       struct ipa_jump_func *jf;
@@ -3680,24 +4189,17 @@ ipa_edge_removal_hook (struct cgraph_edge *cs, void *data ATTRIBUTE_UNUSED)
            rdesc->cs = NULL;
        }
     }
-
-  ipa_free_edge_args_substructures (IPA_EDGE_REF (cs));
 }
 
-/* Hook that is called by cgraph.c when an edge is duplicated.  */
+/* Method invoked when an edge is duplicated.  Copy ipa_edge_args and adjust
+   reference count data strucutres accordingly.  */
 
-static void
-ipa_edge_duplication_hook (struct cgraph_edge *src, struct cgraph_edge *dst,
-                          void *)
+void
+ipa_edge_args_sum_t::duplicate (cgraph_edge *src, cgraph_edge *dst,
+                               ipa_edge_args *old_args, ipa_edge_args *new_args)
 {
-  struct ipa_edge_args *old_args, *new_args;
   unsigned int i;
 
-  ipa_check_create_edge_args ();
-
-  old_args = IPA_EDGE_REF (src);
-  new_args = IPA_EDGE_REF (dst);
-
   new_args->jump_functions = vec_safe_copy (old_args->jump_functions);
   if (old_args->polymorphic_call_contexts)
     new_args->polymorphic_call_contexts
@@ -3749,16 +4251,16 @@ ipa_edge_duplication_hook (struct cgraph_edge *src, struct cgraph_edge *dst,
                 We need to find the duplicate that refers to our tree of
                 inline clones.  */
 
-             gcc_assert (dst->caller->global.inlined_to);
+             gcc_assert (dst->caller->inlined_to);
              for (dst_rdesc = src_rdesc->next_duplicate;
                   dst_rdesc;
                   dst_rdesc = dst_rdesc->next_duplicate)
                {
                  struct cgraph_node *top;
-                 top = dst_rdesc->cs->caller->global.inlined_to
-                   ? dst_rdesc->cs->caller->global.inlined_to
+                 top = dst_rdesc->cs->caller->inlined_to
+                   ? dst_rdesc->cs->caller->inlined_to
                    : dst_rdesc->cs->caller;
-                 if (dst->caller->global.inlined_to == top)
+                 if (dst->caller->inlined_to == top)
                    break;
                }
              gcc_assert (dst_rdesc);
@@ -3768,9 +4270,9 @@ ipa_edge_duplication_hook (struct cgraph_edge *src, struct cgraph_edge *dst,
       else if (dst_jf->type == IPA_JF_PASS_THROUGH
               && src->caller == dst->caller)
        {
-         struct cgraph_node *inline_root = dst->caller->global.inlined_to
-           ? dst->caller->global.inlined_to : dst->caller;
-         struct ipa_node_params *root_info = IPA_NODE_REF (inline_root);
+         struct cgraph_node *inline_root = dst->caller->inlined_to
+           ? dst->caller->inlined_to : dst->caller;
+         class ipa_node_params *root_info = IPA_NODE_REF (inline_root);
          int idx = ipa_get_jf_pass_through_formal_id (dst_jf);
 
          int c = ipa_get_controlled_uses (root_info, idx);
@@ -3801,9 +4303,11 @@ ipa_node_params_t::duplicate(cgraph_node *src, cgraph_node *dst,
 {
   ipa_agg_replacement_value *old_av, *new_av;
 
-  new_info->descriptors = old_info->descriptors.copy ();
+  new_info->descriptors = vec_safe_copy (old_info->descriptors);
   new_info->lattices = NULL;
   new_info->ipcp_orig_node = old_info->ipcp_orig_node;
+  new_info->known_csts = old_info->known_csts.copy ();
+  new_info->known_contexts = old_info->known_contexts.copy ();
 
   new_info->analysis_done = old_info->analysis_done;
   new_info->node_enqueued = old_info->node_enqueued;
@@ -3825,34 +4329,28 @@ ipa_node_params_t::duplicate(cgraph_node *src, cgraph_node *dst,
        }
       ipa_set_node_agg_value_chain (dst, new_av);
     }
+}
 
-  ipcp_transformation_summary *src_trans = ipcp_get_transformation_summary (src);
-
-  if (src_trans)
-    {
-      ipcp_grow_transformations_if_necessary ();
-      src_trans = ipcp_get_transformation_summary (src);
-      const vec<ipa_vr, va_gc> *src_vr = src_trans->m_vr;
-      vec<ipa_vr, va_gc> *&dst_vr
-       = ipcp_get_transformation_summary (dst)->m_vr;
-      if (vec_safe_length (src_trans->m_vr) > 0)
-       {
-         vec_safe_reserve_exact (dst_vr, src_vr->length ());
-         for (unsigned i = 0; i < src_vr->length (); ++i)
-           dst_vr->quick_push ((*src_vr)[i]);
-       }
-    }
+/* Duplication of ipcp transformation summaries.  */
 
-  if (src_trans && vec_safe_length (src_trans->bits) > 0)
+void
+ipcp_transformation_t::duplicate(cgraph_node *, cgraph_node *dst,
+                                ipcp_transformation *src_trans,
+                                ipcp_transformation *dst_trans)
+{
+  /* Avoid redundant work of duplicating vectors we will never use.  */
+  if (dst->inlined_to)
+    return;
+  dst_trans->bits = vec_safe_copy (src_trans->bits);
+  dst_trans->m_vr = vec_safe_copy (src_trans->m_vr);
+  ipa_agg_replacement_value *agg = src_trans->agg_values,
+                           **aggptr = &dst_trans->agg_values;
+  while (agg)
     {
-      ipcp_grow_transformations_if_necessary ();
-      src_trans = ipcp_get_transformation_summary (src);
-      const vec<ipa_bits, va_gc> *src_bits = src_trans->bits;
-      vec<ipa_bits, va_gc> *&dst_bits
-       = ipcp_get_transformation_summary (dst)->bits;
-      vec_safe_reserve_exact (dst_bits, src_bits->length ());
-      for (unsigned i = 0; i < src_bits->length (); ++i)
-       dst_bits->quick_push ((*src_bits)[i]);
+      *aggptr = ggc_alloc<ipa_agg_replacement_value> ();
+      **aggptr = *agg;
+      agg = agg->next;
+      aggptr = &(*aggptr)->next;
     }
 }
 
@@ -3862,13 +4360,8 @@ void
 ipa_register_cgraph_hooks (void)
 {
   ipa_check_create_node_params ();
+  ipa_check_create_edge_args ();
 
-  if (!edge_removal_hook_holder)
-    edge_removal_hook_holder =
-      symtab->add_edge_removal_hook (&ipa_edge_removal_hook, NULL);
-  if (!edge_duplication_hook_holder)
-    edge_duplication_hook_holder =
-      symtab->add_edge_duplication_hook (&ipa_edge_duplication_hook, NULL);
   function_insertion_hook_holder =
       symtab->add_cgraph_insertion_hook (&ipa_add_new_function, NULL);
 }
@@ -3878,10 +4371,6 @@ ipa_register_cgraph_hooks (void)
 static void
 ipa_unregister_cgraph_hooks (void)
 {
-  symtab->remove_edge_removal_hook (edge_removal_hook_holder);
-  edge_removal_hook_holder = NULL;
-  symtab->remove_edge_duplication_hook (edge_duplication_hook_holder);
-  edge_duplication_hook_holder = NULL;
   symtab->remove_cgraph_insertion_hook (function_insertion_hook_holder);
   function_insertion_hook_holder = NULL;
 }
@@ -3928,13 +4417,17 @@ void
 ipa_print_node_params (FILE *f, struct cgraph_node *node)
 {
   int i, count;
-  struct ipa_node_params *info;
+  class ipa_node_params *info;
 
   if (!node->definition)
     return;
   info = IPA_NODE_REF (node);
-  fprintf (f, "  function  %s/%i parameter descriptors:\n",
-          node->name (), node->order);
+  fprintf (f, "  function  %s parameter descriptors:\n", node->dump_name ());
+  if (!info)
+    {
+      fprintf (f, " no params return\n");
+      return;
+    }
   count = ipa_get_param_count (info);
   for (i = 0; i < count; i++)
     {
@@ -3944,6 +4437,12 @@ ipa_print_node_params (FILE *f, struct cgraph_node *node)
       ipa_dump_param (f, info, i);
       if (ipa_is_param_used (info, i))
        fprintf (f, " used");
+      if (ipa_is_param_used_by_ipa_predicates (info, i))
+       fprintf (f, " used_by_ipa_predicates");
+      if (ipa_is_param_used_by_indirect_call (info, i))
+       fprintf (f, " used_by_indirect_call");
+      if (ipa_is_param_used_by_polymorphic_call (info, i))
+       fprintf (f, " used_by_polymorphic_call");
       c = ipa_get_controlled_uses (info, i);
       if (c == IPA_UNDESCRIBED_USE)
        fprintf (f, " undescribed_use");
@@ -3966,847 +4465,172 @@ ipa_print_all_params (FILE * f)
     ipa_print_node_params (f, node);
 }
 
-/* Return a heap allocated vector containing formal parameters of FNDECL.  */
+/* Dump the AV linked list.  */
 
-vec<tree> 
-ipa_get_vector_of_formal_parms (tree fndecl)
+void
+ipa_dump_agg_replacement_values (FILE *f, struct ipa_agg_replacement_value *av)
 {
-  vec<tree> args;
-  int count;
-  tree parm;
-
-  gcc_assert (!flag_wpa);
-  count = count_formal_params (fndecl);
-  args.create (count);
-  for (parm = DECL_ARGUMENTS (fndecl); parm; parm = DECL_CHAIN (parm))
-    args.quick_push (parm);
-
-  return args;
+  bool comma = false;
+  fprintf (f, "     Aggregate replacements:");
+  for (; av; av = av->next)
+    {
+      fprintf (f, "%s %i[" HOST_WIDE_INT_PRINT_DEC "]=", comma ? "," : "",
+              av->index, av->offset);
+      print_generic_expr (f, av->value);
+      comma = true;
+    }
+  fprintf (f, "\n");
 }
 
-/* Return a heap allocated vector containing types of formal parameters of
-   function type FNTYPE.  */
+/* Stream out jump function JUMP_FUNC to OB.  */
 
-vec<tree>
-ipa_get_vector_of_formal_parm_types (tree fntype)
+static void
+ipa_write_jump_function (struct output_block *ob,
+                        struct ipa_jump_func *jump_func)
 {
-  vec<tree> types;
-  int count = 0;
-  tree t;
-
-  for (t = TYPE_ARG_TYPES (fntype); t; t = TREE_CHAIN (t))
-    count++;
-
-  types.create (count);
-  for (t = TYPE_ARG_TYPES (fntype); t; t = TREE_CHAIN (t))
-    types.quick_push (TREE_VALUE (t));
-
-  return types;
-}
-
-/* Modify the function declaration FNDECL and its type according to the plan in
-   ADJUSTMENTS.  It also sets base fields of individual adjustments structures
-   to reflect the actual parameters being modified which are determined by the
-   base_index field.  */
+  struct ipa_agg_jf_item *item;
+  struct bitpack_d bp;
+  int i, count;
+  int flag = 0;
 
-void
-ipa_modify_formal_parameters (tree fndecl, ipa_parm_adjustment_vec adjustments)
-{
-  vec<tree> oparms = ipa_get_vector_of_formal_parms (fndecl);
-  tree orig_type = TREE_TYPE (fndecl);
-  tree old_arg_types = TYPE_ARG_TYPES (orig_type);
-
-  /* The following test is an ugly hack, some functions simply don't have any
-     arguments in their type.  This is probably a bug but well... */
-  bool care_for_types = (old_arg_types != NULL_TREE);
-  bool last_parm_void;
-  vec<tree> otypes;
-  if (care_for_types)
-    {
-      last_parm_void = (TREE_VALUE (tree_last (old_arg_types))
-                       == void_type_node);
-      otypes = ipa_get_vector_of_formal_parm_types (orig_type);
-      if (last_parm_void)
-       gcc_assert (oparms.length () + 1 == otypes.length ());
-      else
-       gcc_assert (oparms.length () == otypes.length ());
-    }
-  else
-    {
-      last_parm_void = false;
-      otypes.create (0);
-    }
+  /* ADDR_EXPRs are very comon IP invariants; save some streamer data
+     as well as WPA memory by handling them specially.  */
+  if (jump_func->type == IPA_JF_CONST
+      && TREE_CODE (jump_func->value.constant.value) == ADDR_EXPR)
+    flag = 1;
 
-  int len = adjustments.length ();
-  tree *link = &DECL_ARGUMENTS (fndecl);
-  tree new_arg_types = NULL;
-  for (int i = 0; i < len; i++)
+  streamer_write_uhwi (ob, jump_func->type * 2 + flag);
+  switch (jump_func->type)
     {
-      struct ipa_parm_adjustment *adj;
-      gcc_assert (link);
-
-      adj = &adjustments[i];
-      tree parm;
-      if (adj->op == IPA_PARM_OP_NEW)
-       parm = NULL;
-      else
-       parm = oparms[adj->base_index];
-      adj->base = parm;
-
-      if (adj->op == IPA_PARM_OP_COPY)
+    case IPA_JF_UNKNOWN:
+      break;
+    case IPA_JF_CONST:
+      gcc_assert (
+         EXPR_LOCATION (jump_func->value.constant.value) == UNKNOWN_LOCATION);
+      stream_write_tree (ob,
+                        flag
+                        ? TREE_OPERAND (jump_func->value.constant.value, 0)
+                        : jump_func->value.constant.value, true);
+      break;
+    case IPA_JF_PASS_THROUGH:
+      streamer_write_uhwi (ob, jump_func->value.pass_through.operation);
+      if (jump_func->value.pass_through.operation == NOP_EXPR)
        {
-         if (care_for_types)
-           new_arg_types = tree_cons (NULL_TREE, otypes[adj->base_index],
-                                      new_arg_types);
-         *link = parm;
-         link = &DECL_CHAIN (parm);
+         streamer_write_uhwi (ob, jump_func->value.pass_through.formal_id);
+         bp = bitpack_create (ob->main_stream);
+         bp_pack_value (&bp, jump_func->value.pass_through.agg_preserved, 1);
+         streamer_write_bitpack (&bp);
        }
-      else if (adj->op != IPA_PARM_OP_REMOVE)
+      else if (TREE_CODE_CLASS (jump_func->value.pass_through.operation)
+              == tcc_unary)
+       streamer_write_uhwi (ob, jump_func->value.pass_through.formal_id);
+      else
        {
-         tree new_parm;
-         tree ptype;
-
-         if (adj->by_ref)
-           ptype = build_pointer_type (adj->type);
-         else
-           {
-             ptype = adj->type;
-             if (is_gimple_reg_type (ptype))
-               {
-                 unsigned malign = GET_MODE_ALIGNMENT (TYPE_MODE (ptype));
-                 if (TYPE_ALIGN (ptype) != malign)
-                   ptype = build_aligned_type (ptype, malign);
-               }
-           }
-
-         if (care_for_types)
-           new_arg_types = tree_cons (NULL_TREE, ptype, new_arg_types);
-
-         new_parm = build_decl (UNKNOWN_LOCATION, PARM_DECL, NULL_TREE,
-                                ptype);
-         const char *prefix = adj->arg_prefix ? adj->arg_prefix : "SYNTH";
-         DECL_NAME (new_parm) = create_tmp_var_name (prefix);
-         DECL_ARTIFICIAL (new_parm) = 1;
-         DECL_ARG_TYPE (new_parm) = ptype;
-         DECL_CONTEXT (new_parm) = fndecl;
-         TREE_USED (new_parm) = 1;
-         DECL_IGNORED_P (new_parm) = 1;
-         layout_decl (new_parm, 0);
-
-         if (adj->op == IPA_PARM_OP_NEW)
-           adj->base = NULL;
-         else
-           adj->base = parm;
-         adj->new_decl = new_parm;
-
-         *link = new_parm;
-         link = &DECL_CHAIN (new_parm);
+         stream_write_tree (ob, jump_func->value.pass_through.operand, true);
+         streamer_write_uhwi (ob, jump_func->value.pass_through.formal_id);
        }
+      break;
+    case IPA_JF_ANCESTOR:
+      streamer_write_uhwi (ob, jump_func->value.ancestor.offset);
+      streamer_write_uhwi (ob, jump_func->value.ancestor.formal_id);
+      bp = bitpack_create (ob->main_stream);
+      bp_pack_value (&bp, jump_func->value.ancestor.agg_preserved, 1);
+      streamer_write_bitpack (&bp);
+      break;
+    default:
+      fatal_error (UNKNOWN_LOCATION, "invalid jump function in LTO stream");
     }
 
-  *link = NULL_TREE;
+  count = vec_safe_length (jump_func->agg.items);
+  streamer_write_uhwi (ob, count);
+  if (count)
+    {
+      bp = bitpack_create (ob->main_stream);
+      bp_pack_value (&bp, jump_func->agg.by_ref, 1);
+      streamer_write_bitpack (&bp);
+    }
 
-  tree new_reversed = NULL;
-  if (care_for_types)
+  FOR_EACH_VEC_SAFE_ELT (jump_func->agg.items, i, item)
     {
-      new_reversed = nreverse (new_arg_types);
-      if (last_parm_void)
+      stream_write_tree (ob, item->type, true);
+      streamer_write_uhwi (ob, item->offset);
+      streamer_write_uhwi (ob, item->jftype);
+      switch (item->jftype)
        {
-         if (new_reversed)
-           TREE_CHAIN (new_arg_types) = void_list_node;
-         else
-           new_reversed = void_list_node;
+       case IPA_JF_UNKNOWN:
+         break;
+       case IPA_JF_CONST:
+         stream_write_tree (ob, item->value.constant, true);
+         break;
+       case IPA_JF_PASS_THROUGH:
+       case IPA_JF_LOAD_AGG:
+         streamer_write_uhwi (ob, item->value.pass_through.operation);
+         streamer_write_uhwi (ob, item->value.pass_through.formal_id);
+         if (TREE_CODE_CLASS (item->value.pass_through.operation)
+                                                       != tcc_unary)
+           stream_write_tree (ob, item->value.pass_through.operand, true);
+         if (item->jftype == IPA_JF_LOAD_AGG)
+           {
+             stream_write_tree (ob, item->value.load_agg.type, true);
+             streamer_write_uhwi (ob, item->value.load_agg.offset);
+             bp = bitpack_create (ob->main_stream);
+             bp_pack_value (&bp, item->value.load_agg.by_ref, 1);
+             streamer_write_bitpack (&bp);
+           }
+         break;
+       default:
+         fatal_error (UNKNOWN_LOCATION,
+                      "invalid jump function in LTO stream");
        }
     }
 
-  /* Use copy_node to preserve as much as possible from original type
-     (debug info, attribute lists etc.)
-     Exception is METHOD_TYPEs must have THIS argument.
-     When we are asked to remove it, we need to build new FUNCTION_TYPE
-     instead.  */
-  tree new_type = NULL;
-  if (TREE_CODE (orig_type) != METHOD_TYPE
-       || (adjustments[0].op == IPA_PARM_OP_COPY
-         && adjustments[0].base_index == 0))
+  bp = bitpack_create (ob->main_stream);
+  bp_pack_value (&bp, !!jump_func->bits, 1);
+  streamer_write_bitpack (&bp);
+  if (jump_func->bits)
     {
-      new_type = build_distinct_type_copy (orig_type);
-      TYPE_ARG_TYPES (new_type) = new_reversed;
+      streamer_write_widest_int (ob, jump_func->bits->value);
+      streamer_write_widest_int (ob, jump_func->bits->mask);
     }
-  else
-    {
-      new_type
-        = build_distinct_type_copy (build_function_type (TREE_TYPE (orig_type),
-                                                        new_reversed));
-      TYPE_CONTEXT (new_type) = TYPE_CONTEXT (orig_type);
-      DECL_VINDEX (fndecl) = NULL_TREE;
-    }
-
-  /* When signature changes, we need to clear builtin info.  */
-  if (DECL_BUILT_IN (fndecl))
-    {
-      DECL_BUILT_IN_CLASS (fndecl) = NOT_BUILT_IN;
-      DECL_FUNCTION_CODE (fndecl) = (enum built_in_function) 0;
-    }
-
-  TREE_TYPE (fndecl) = new_type;
-  DECL_VIRTUAL_P (fndecl) = 0;
-  DECL_LANG_SPECIFIC (fndecl) = NULL;
-  otypes.release ();
-  oparms.release ();
-}
-
-/* Modify actual arguments of a function call CS as indicated in ADJUSTMENTS.
-   If this is a directly recursive call, CS must be NULL.  Otherwise it must
-   contain the corresponding call graph edge.  */
-
-void
-ipa_modify_call_arguments (struct cgraph_edge *cs, gcall *stmt,
-                          ipa_parm_adjustment_vec adjustments)
-{
-  struct cgraph_node *current_node = cgraph_node::get (current_function_decl);
-  vec<tree> vargs;
-  vec<tree, va_gc> **debug_args = NULL;
-  gcall *new_stmt;
-  gimple_stmt_iterator gsi, prev_gsi;
-  tree callee_decl;
-  int i, len;
-
-  len = adjustments.length ();
-  vargs.create (len);
-  callee_decl = !cs ? gimple_call_fndecl (stmt) : cs->callee->decl;
-  current_node->remove_stmt_references (stmt);
-
-  gsi = gsi_for_stmt (stmt);
-  prev_gsi = gsi;
-  gsi_prev (&prev_gsi);
-  for (i = 0; i < len; i++)
-    {
-      struct ipa_parm_adjustment *adj;
-
-      adj = &adjustments[i];
-
-      if (adj->op == IPA_PARM_OP_COPY)
-       {
-         tree arg = gimple_call_arg (stmt, adj->base_index);
-
-         vargs.quick_push (arg);
-       }
-      else if (adj->op != IPA_PARM_OP_REMOVE)
-       {
-         tree expr, base, off;
-         location_t loc;
-         unsigned int deref_align = 0;
-         bool deref_base = false;
-
-         /* We create a new parameter out of the value of the old one, we can
-            do the following kind of transformations:
-
-            - A scalar passed by reference is converted to a scalar passed by
-               value.  (adj->by_ref is false and the type of the original
-               actual argument is a pointer to a scalar).
-
-             - A part of an aggregate is passed instead of the whole aggregate.
-               The part can be passed either by value or by reference, this is
-               determined by value of adj->by_ref.  Moreover, the code below
-               handles both situations when the original aggregate is passed by
-               value (its type is not a pointer) and when it is passed by
-               reference (it is a pointer to an aggregate).
-
-            When the new argument is passed by reference (adj->by_ref is true)
-            it must be a part of an aggregate and therefore we form it by
-            simply taking the address of a reference inside the original
-            aggregate.  */
-
-         gcc_checking_assert (adj->offset % BITS_PER_UNIT == 0);
-         base = gimple_call_arg (stmt, adj->base_index);
-         loc = DECL_P (base) ? DECL_SOURCE_LOCATION (base)
-                             : EXPR_LOCATION (base);
-
-         if (TREE_CODE (base) != ADDR_EXPR
-             && POINTER_TYPE_P (TREE_TYPE (base)))
-           off = build_int_cst (adj->alias_ptr_type,
-                                adj->offset / BITS_PER_UNIT);
-         else
-           {
-             HOST_WIDE_INT base_offset;
-             tree prev_base;
-             bool addrof;
-
-             if (TREE_CODE (base) == ADDR_EXPR)
-               {
-                 base = TREE_OPERAND (base, 0);
-                 addrof = true;
-               }
-             else
-               addrof = false;
-             prev_base = base;
-             base = get_addr_base_and_unit_offset (base, &base_offset);
-             /* Aggregate arguments can have non-invariant addresses.  */
-             if (!base)
-               {
-                 base = build_fold_addr_expr (prev_base);
-                 off = build_int_cst (adj->alias_ptr_type,
-                                      adj->offset / BITS_PER_UNIT);
-               }
-             else if (TREE_CODE (base) == MEM_REF)
-               {
-                 if (!addrof)
-                   {
-                     deref_base = true;
-                     deref_align = TYPE_ALIGN (TREE_TYPE (base));
-                   }
-                 off = build_int_cst (adj->alias_ptr_type,
-                                      base_offset
-                                      + adj->offset / BITS_PER_UNIT);
-                 off = int_const_binop (PLUS_EXPR, TREE_OPERAND (base, 1),
-                                        off);
-                 base = TREE_OPERAND (base, 0);
-               }
-             else
-               {
-                 off = build_int_cst (adj->alias_ptr_type,
-                                      base_offset
-                                      + adj->offset / BITS_PER_UNIT);
-                 base = build_fold_addr_expr (base);
-               }
-           }
-
-         if (!adj->by_ref)
-           {
-             tree type = adj->type;
-             unsigned int align;
-             unsigned HOST_WIDE_INT misalign;
-
-             if (deref_base)
-               {
-                 align = deref_align;
-                 misalign = 0;
-               }
-             else
-               {
-                 get_pointer_alignment_1 (base, &align, &misalign);
-                 if (TYPE_ALIGN (type) > align)
-                   align = TYPE_ALIGN (type);
-               }
-             misalign += (offset_int::from (off, SIGNED).to_short_addr ()
-                          * BITS_PER_UNIT);
-             misalign = misalign & (align - 1);
-             if (misalign != 0)
-               align = least_bit_hwi (misalign);
-             if (align < TYPE_ALIGN (type))
-               type = build_aligned_type (type, align);
-             base = force_gimple_operand_gsi (&gsi, base,
-                                              true, NULL, true, GSI_SAME_STMT);
-             expr = fold_build2_loc (loc, MEM_REF, type, base, off);
-             REF_REVERSE_STORAGE_ORDER (expr) = adj->reverse;
-             /* If expr is not a valid gimple call argument emit
-                a load into a temporary.  */
-             if (is_gimple_reg_type (TREE_TYPE (expr)))
-               {
-                 gimple *tem = gimple_build_assign (NULL_TREE, expr);
-                 if (gimple_in_ssa_p (cfun))
-                   {
-                     gimple_set_vuse (tem, gimple_vuse (stmt));
-                     expr = make_ssa_name (TREE_TYPE (expr), tem);
-                   }
-                 else
-                   expr = create_tmp_reg (TREE_TYPE (expr));
-                 gimple_assign_set_lhs (tem, expr);
-                 gsi_insert_before (&gsi, tem, GSI_SAME_STMT);
-               }
-           }
-         else
-           {
-             expr = fold_build2_loc (loc, MEM_REF, adj->type, base, off);
-             REF_REVERSE_STORAGE_ORDER (expr) = adj->reverse;
-             expr = build_fold_addr_expr (expr);
-             expr = force_gimple_operand_gsi (&gsi, expr,
-                                              true, NULL, true, GSI_SAME_STMT);
-           }
-         vargs.quick_push (expr);
-       }
-      if (adj->op != IPA_PARM_OP_COPY && MAY_HAVE_DEBUG_STMTS)
-       {
-         unsigned int ix;
-         tree ddecl = NULL_TREE, origin = DECL_ORIGIN (adj->base), arg;
-         gimple *def_temp;
-
-         arg = gimple_call_arg (stmt, adj->base_index);
-         if (!useless_type_conversion_p (TREE_TYPE (origin), TREE_TYPE (arg)))
-           {
-             if (!fold_convertible_p (TREE_TYPE (origin), arg))
-               continue;
-             arg = fold_convert_loc (gimple_location (stmt),
-                                     TREE_TYPE (origin), arg);
-           }
-         if (debug_args == NULL)
-           debug_args = decl_debug_args_insert (callee_decl);
-         for (ix = 0; vec_safe_iterate (*debug_args, ix, &ddecl); ix += 2)
-           if (ddecl == origin)
-             {
-               ddecl = (**debug_args)[ix + 1];
-               break;
-             }
-         if (ddecl == NULL)
-           {
-             ddecl = make_node (DEBUG_EXPR_DECL);
-             DECL_ARTIFICIAL (ddecl) = 1;
-             TREE_TYPE (ddecl) = TREE_TYPE (origin);
-             SET_DECL_MODE (ddecl, DECL_MODE (origin));
-
-             vec_safe_push (*debug_args, origin);
-             vec_safe_push (*debug_args, ddecl);
-           }
-         def_temp = gimple_build_debug_bind (ddecl, unshare_expr (arg), stmt);
-         gsi_insert_before (&gsi, def_temp, GSI_SAME_STMT);
-       }
-    }
-
-  if (dump_file && (dump_flags & TDF_DETAILS))
-    {
-      fprintf (dump_file, "replacing stmt:");
-      print_gimple_stmt (dump_file, gsi_stmt (gsi), 0, 0);
-    }
-
-  new_stmt = gimple_build_call_vec (callee_decl, vargs);
-  vargs.release ();
-  if (gimple_call_lhs (stmt))
-    gimple_call_set_lhs (new_stmt, gimple_call_lhs (stmt));
-
-  gimple_set_block (new_stmt, gimple_block (stmt));
-  if (gimple_has_location (stmt))
-    gimple_set_location (new_stmt, gimple_location (stmt));
-  gimple_call_set_chain (new_stmt, gimple_call_chain (stmt));
-  gimple_call_copy_flags (new_stmt, stmt);
-  if (gimple_in_ssa_p (cfun))
-    {
-      gimple_set_vuse (new_stmt, gimple_vuse (stmt));
-      if (gimple_vdef (stmt))
-       {
-         gimple_set_vdef (new_stmt, gimple_vdef (stmt));
-         SSA_NAME_DEF_STMT (gimple_vdef (new_stmt)) = new_stmt;
-       }
-    }
-
-  if (dump_file && (dump_flags & TDF_DETAILS))
-    {
-      fprintf (dump_file, "with stmt:");
-      print_gimple_stmt (dump_file, new_stmt, 0, 0);
-      fprintf (dump_file, "\n");
-    }
-  gsi_replace (&gsi, new_stmt, true);
-  if (cs)
-    cs->set_call_stmt (new_stmt);
-  do
-    {
-      current_node->record_stmt_references (gsi_stmt (gsi));
-      gsi_prev (&gsi);
-    }
-  while (gsi_stmt (gsi) != gsi_stmt (prev_gsi));
-}
-
-/* If the expression *EXPR should be replaced by a reduction of a parameter, do
-   so.  ADJUSTMENTS is a pointer to a vector of adjustments.  CONVERT
-   specifies whether the function should care about type incompatibility the
-   current and new expressions.  If it is false, the function will leave
-   incompatibility issues to the caller.  Return true iff the expression
-   was modified. */
-
-bool
-ipa_modify_expr (tree *expr, bool convert,
-                ipa_parm_adjustment_vec adjustments)
-{
-  struct ipa_parm_adjustment *cand
-    = ipa_get_adjustment_candidate (&expr, &convert, adjustments, false);
-  if (!cand)
-    return false;
-
-  tree src;
-  if (cand->by_ref)
-    {
-      src = build_simple_mem_ref (cand->new_decl);
-      REF_REVERSE_STORAGE_ORDER (src) = cand->reverse;
-    }
-  else
-    src = cand->new_decl;
-
-  if (dump_file && (dump_flags & TDF_DETAILS))
-    {
-      fprintf (dump_file, "About to replace expr ");
-      print_generic_expr (dump_file, *expr, 0);
-      fprintf (dump_file, " with ");
-      print_generic_expr (dump_file, src, 0);
-      fprintf (dump_file, "\n");
-    }
-
-  if (convert && !useless_type_conversion_p (TREE_TYPE (*expr), cand->type))
-    {
-      tree vce = build1 (VIEW_CONVERT_EXPR, TREE_TYPE (*expr), src);
-      *expr = vce;
-    }
-  else
-    *expr = src;
-  return true;
-}
-
-/* If T is an SSA_NAME, return NULL if it is not a default def or
-   return its base variable if it is.  If IGNORE_DEFAULT_DEF is true,
-   the base variable is always returned, regardless if it is a default
-   def.  Return T if it is not an SSA_NAME.  */
-
-static tree
-get_ssa_base_param (tree t, bool ignore_default_def)
-{
-  if (TREE_CODE (t) == SSA_NAME)
-    {
-      if (ignore_default_def || SSA_NAME_IS_DEFAULT_DEF (t))
-       return SSA_NAME_VAR (t);
-      else
-       return NULL_TREE;
-    }
-  return t;
-}
-
-/* Given an expression, return an adjustment entry specifying the
-   transformation to be done on EXPR.  If no suitable adjustment entry
-   was found, returns NULL.
-
-   If IGNORE_DEFAULT_DEF is set, consider SSA_NAMEs which are not a
-   default def, otherwise bail on them.
-
-   If CONVERT is non-NULL, this function will set *CONVERT if the
-   expression provided is a component reference.  ADJUSTMENTS is the
-   adjustments vector.  */
-
-ipa_parm_adjustment *
-ipa_get_adjustment_candidate (tree **expr, bool *convert,
-                             ipa_parm_adjustment_vec adjustments,
-                             bool ignore_default_def)
-{
-  if (TREE_CODE (**expr) == BIT_FIELD_REF
-      || TREE_CODE (**expr) == IMAGPART_EXPR
-      || TREE_CODE (**expr) == REALPART_EXPR)
-    {
-      *expr = &TREE_OPERAND (**expr, 0);
-      if (convert)
-       *convert = true;
-    }
-
-  HOST_WIDE_INT offset, size, max_size;
-  bool reverse;
-  tree base
-    = get_ref_base_and_extent (**expr, &offset, &size, &max_size, &reverse);
-  if (!base || size == -1 || max_size == -1)
-    return NULL;
-
-  if (TREE_CODE (base) == MEM_REF)
-    {
-      offset += mem_ref_offset (base).to_short_addr () * BITS_PER_UNIT;
-      base = TREE_OPERAND (base, 0);
-    }
-
-  base = get_ssa_base_param (base, ignore_default_def);
-  if (!base || TREE_CODE (base) != PARM_DECL)
-    return NULL;
-
-  struct ipa_parm_adjustment *cand = NULL;
-  unsigned int len = adjustments.length ();
-  for (unsigned i = 0; i < len; i++)
-    {
-      struct ipa_parm_adjustment *adj = &adjustments[i];
-
-      if (adj->base == base
-         && (adj->offset == offset || adj->op == IPA_PARM_OP_REMOVE))
-       {
-         cand = adj;
-         break;
-       }
-    }
-
-  if (!cand || cand->op == IPA_PARM_OP_COPY || cand->op == IPA_PARM_OP_REMOVE)
-    return NULL;
-  return cand;
-}
-
-/* Return true iff BASE_INDEX is in ADJUSTMENTS more than once.  */
-
-static bool
-index_in_adjustments_multiple_times_p (int base_index,
-                                      ipa_parm_adjustment_vec adjustments)
-{
-  int i, len = adjustments.length ();
-  bool one = false;
-
-  for (i = 0; i < len; i++)
-    {
-      struct ipa_parm_adjustment *adj;
-      adj = &adjustments[i];
-
-      if (adj->base_index == base_index)
-       {
-         if (one)
-           return true;
-         else
-           one = true;
-       }
-    }
-  return false;
-}
-
-
-/* Return adjustments that should have the same effect on function parameters
-   and call arguments as if they were first changed according to adjustments in
-   INNER and then by adjustments in OUTER.  */
-
-ipa_parm_adjustment_vec
-ipa_combine_adjustments (ipa_parm_adjustment_vec inner,
-                        ipa_parm_adjustment_vec outer)
-{
-  int i, outlen = outer.length ();
-  int inlen = inner.length ();
-  int removals = 0;
-  ipa_parm_adjustment_vec adjustments, tmp;
-
-  tmp.create (inlen);
-  for (i = 0; i < inlen; i++)
-    {
-      struct ipa_parm_adjustment *n;
-      n = &inner[i];
-
-      if (n->op == IPA_PARM_OP_REMOVE)
-       removals++;
-      else
-       {
-         /* FIXME: Handling of new arguments are not implemented yet.  */
-         gcc_assert (n->op != IPA_PARM_OP_NEW);
-         tmp.quick_push (*n);
-       }
-    }
-
-  adjustments.create (outlen + removals);
-  for (i = 0; i < outlen; i++)
-    {
-      struct ipa_parm_adjustment r;
-      struct ipa_parm_adjustment *out = &outer[i];
-      struct ipa_parm_adjustment *in = &tmp[out->base_index];
-
-      memset (&r, 0, sizeof (r));
-      gcc_assert (in->op != IPA_PARM_OP_REMOVE);
-      if (out->op == IPA_PARM_OP_REMOVE)
-       {
-         if (!index_in_adjustments_multiple_times_p (in->base_index, tmp))
-           {
-             r.op = IPA_PARM_OP_REMOVE;
-             adjustments.quick_push (r);
-           }
-         continue;
-       }
-      else
-       {
-         /* FIXME: Handling of new arguments are not implemented yet.  */
-         gcc_assert (out->op != IPA_PARM_OP_NEW);
-       }
-
-      r.base_index = in->base_index;
-      r.type = out->type;
-
-      /* FIXME:  Create nonlocal value too.  */
-
-      if (in->op == IPA_PARM_OP_COPY && out->op == IPA_PARM_OP_COPY)
-       r.op = IPA_PARM_OP_COPY;
-      else if (in->op == IPA_PARM_OP_COPY)
-       r.offset = out->offset;
-      else if (out->op == IPA_PARM_OP_COPY)
-       r.offset = in->offset;
-      else
-       r.offset = in->offset + out->offset;
-      adjustments.quick_push (r);
-    }
-
-  for (i = 0; i < inlen; i++)
-    {
-      struct ipa_parm_adjustment *n = &inner[i];
-
-      if (n->op == IPA_PARM_OP_REMOVE)
-       adjustments.quick_push (*n);
-    }
-
-  tmp.release ();
-  return adjustments;
-}
-
-/* Dump the adjustments in the vector ADJUSTMENTS to dump_file in a human
-   friendly way, assuming they are meant to be applied to FNDECL.  */
-
-void
-ipa_dump_param_adjustments (FILE *file, ipa_parm_adjustment_vec adjustments,
-                           tree fndecl)
-{
-  int i, len = adjustments.length ();
-  bool first = true;
-  vec<tree> parms = ipa_get_vector_of_formal_parms (fndecl);
-
-  fprintf (file, "IPA param adjustments: ");
-  for (i = 0; i < len; i++)
-    {
-      struct ipa_parm_adjustment *adj;
-      adj = &adjustments[i];
-
-      if (!first)
-       fprintf (file, "                 ");
-      else
-       first = false;
-
-      fprintf (file, "%i. base_index: %i - ", i, adj->base_index);
-      print_generic_expr (file, parms[adj->base_index], 0);
-      if (adj->base)
-       {
-         fprintf (file, ", base: ");
-         print_generic_expr (file, adj->base, 0);
-       }
-      if (adj->new_decl)
-       {
-         fprintf (file, ", new_decl: ");
-         print_generic_expr (file, adj->new_decl, 0);
-       }
-      if (adj->new_ssa_base)
-       {
-         fprintf (file, ", new_ssa_base: ");
-         print_generic_expr (file, adj->new_ssa_base, 0);
-       }
-
-      if (adj->op == IPA_PARM_OP_COPY)
-       fprintf (file, ", copy_param");
-      else if (adj->op == IPA_PARM_OP_REMOVE)
-       fprintf (file, ", remove_param");
-      else
-       fprintf (file, ", offset %li", (long) adj->offset);
-      if (adj->by_ref)
-       fprintf (file, ", by_ref");
-      print_node_brief (file, ", type: ", adj->type, 0);
-      fprintf (file, "\n");
-    }
-  parms.release ();
-}
-
-/* Dump the AV linked list.  */
-
-void
-ipa_dump_agg_replacement_values (FILE *f, struct ipa_agg_replacement_value *av)
-{
-  bool comma = false;
-  fprintf (f, "     Aggregate replacements:");
-  for (; av; av = av->next)
-    {
-      fprintf (f, "%s %i[" HOST_WIDE_INT_PRINT_DEC "]=", comma ? "," : "",
-              av->index, av->offset);
-      print_generic_expr (f, av->value, 0);
-      comma = true;
-    }
-  fprintf (f, "\n");
-}
-
-/* Stream out jump function JUMP_FUNC to OB.  */
-
-static void
-ipa_write_jump_function (struct output_block *ob,
-                        struct ipa_jump_func *jump_func)
-{
-  struct ipa_agg_jf_item *item;
-  struct bitpack_d bp;
-  int i, count;
-
-  streamer_write_uhwi (ob, jump_func->type);
-  switch (jump_func->type)
-    {
-    case IPA_JF_UNKNOWN:
-      break;
-    case IPA_JF_CONST:
-      gcc_assert (
-         EXPR_LOCATION (jump_func->value.constant.value) == UNKNOWN_LOCATION);
-      stream_write_tree (ob, jump_func->value.constant.value, true);
-      break;
-    case IPA_JF_PASS_THROUGH:
-      streamer_write_uhwi (ob, jump_func->value.pass_through.operation);
-      if (jump_func->value.pass_through.operation == NOP_EXPR)
-       {
-         streamer_write_uhwi (ob, jump_func->value.pass_through.formal_id);
-         bp = bitpack_create (ob->main_stream);
-         bp_pack_value (&bp, jump_func->value.pass_through.agg_preserved, 1);
-         streamer_write_bitpack (&bp);
-       }
-      else if (TREE_CODE_CLASS (jump_func->value.pass_through.operation)
-              == tcc_unary)
-       streamer_write_uhwi (ob, jump_func->value.pass_through.formal_id);
-      else
-       {
-         stream_write_tree (ob, jump_func->value.pass_through.operand, true);
-         streamer_write_uhwi (ob, jump_func->value.pass_through.formal_id);
-       }
-      break;
-    case IPA_JF_ANCESTOR:
-      streamer_write_uhwi (ob, jump_func->value.ancestor.offset);
-      streamer_write_uhwi (ob, jump_func->value.ancestor.formal_id);
-      bp = bitpack_create (ob->main_stream);
-      bp_pack_value (&bp, jump_func->value.ancestor.agg_preserved, 1);
-      streamer_write_bitpack (&bp);
-      break;
-    }
-
-  count = vec_safe_length (jump_func->agg.items);
-  streamer_write_uhwi (ob, count);
-  if (count)
-    {
-      bp = bitpack_create (ob->main_stream);
-      bp_pack_value (&bp, jump_func->agg.by_ref, 1);
-      streamer_write_bitpack (&bp);
-    }
-
-  FOR_EACH_VEC_SAFE_ELT (jump_func->agg.items, i, item)
-    {
-      streamer_write_uhwi (ob, item->offset);
-      stream_write_tree (ob, item->value, true);
-    }
-
-  bp = bitpack_create (ob->main_stream);
-  bp_pack_value (&bp, jump_func->bits.known, 1);
-  streamer_write_bitpack (&bp);
-  if (jump_func->bits.known)
-    {
-      streamer_write_widest_int (ob, jump_func->bits.value);
-      streamer_write_widest_int (ob, jump_func->bits.mask);
-    }   
-  bp_pack_value (&bp, jump_func->vr_known, 1);
+  bp_pack_value (&bp, !!jump_func->m_vr, 1);
   streamer_write_bitpack (&bp);
-  if (jump_func->vr_known)
+  if (jump_func->m_vr)
     {
       streamer_write_enum (ob->main_stream, value_rang_type,
-                          VR_LAST, jump_func->m_vr.type);
-      stream_write_tree (ob, jump_func->m_vr.min, true);
-      stream_write_tree (ob, jump_func->m_vr.max, true);
+                          VR_LAST, jump_func->m_vr->kind ());
+      stream_write_tree (ob, jump_func->m_vr->min (), true);
+      stream_write_tree (ob, jump_func->m_vr->max (), true);
     }
 }
 
 /* Read in jump function JUMP_FUNC from IB.  */
 
 static void
-ipa_read_jump_function (struct lto_input_block *ib,
+ipa_read_jump_function (class lto_input_block *ib,
                        struct ipa_jump_func *jump_func,
                        struct cgraph_edge *cs,
-                       struct data_in *data_in)
+                       class data_in *data_in,
+                       bool prevails)
 {
   enum jump_func_type jftype;
   enum tree_code operation;
   int i, count;
+  int val = streamer_read_uhwi (ib);
+  bool flag = val & 1;
 
-  jftype = (enum jump_func_type) streamer_read_uhwi (ib);
+  jftype = (enum jump_func_type) (val / 2);
   switch (jftype)
     {
     case IPA_JF_UNKNOWN:
       ipa_set_jf_unknown (jump_func);
       break;
     case IPA_JF_CONST:
-      ipa_set_jf_constant (jump_func, stream_read_tree (ib, data_in), cs);
+      {
+       tree t = stream_read_tree (ib, data_in);
+       if (flag && prevails)
+         t = build_fold_addr_expr (t);
+       ipa_set_jf_constant (jump_func, t, cs);
+      }
       break;
     case IPA_JF_PASS_THROUGH:
       operation = (enum tree_code) streamer_read_uhwi (ib);
@@ -4839,10 +4663,13 @@ ipa_read_jump_function (struct lto_input_block *ib,
        ipa_set_ancestor_jf (jump_func, offset, formal_id, agg_preserved);
        break;
       }
+    default:
+      fatal_error (UNKNOWN_LOCATION, "invalid jump function in LTO stream");
     }
 
   count = streamer_read_uhwi (ib);
-  vec_alloc (jump_func->agg.items, count);
+  if (prevails)
+    vec_alloc (jump_func->agg.items, count);
   if (count)
     {
       struct bitpack_d bp = streamer_read_bitpack (ib);
@@ -4851,35 +4678,68 @@ ipa_read_jump_function (struct lto_input_block *ib,
   for (i = 0; i < count; i++)
     {
       struct ipa_agg_jf_item item;
+      item.type = stream_read_tree (ib, data_in);
       item.offset = streamer_read_uhwi (ib);
-      item.value = stream_read_tree (ib, data_in);
-      jump_func->agg.items->quick_push (item);
+      item.jftype = (enum jump_func_type) streamer_read_uhwi (ib);
+
+      switch (item.jftype)
+       {
+       case IPA_JF_UNKNOWN:
+         break;
+       case IPA_JF_CONST:
+         item.value.constant = stream_read_tree (ib, data_in);
+         break;
+       case IPA_JF_PASS_THROUGH:
+       case IPA_JF_LOAD_AGG:
+         operation = (enum tree_code) streamer_read_uhwi (ib);
+         item.value.pass_through.operation = operation;
+         item.value.pass_through.formal_id = streamer_read_uhwi (ib);
+         if (TREE_CODE_CLASS (operation) == tcc_unary)
+           item.value.pass_through.operand = NULL_TREE;
+         else
+           item.value.pass_through.operand = stream_read_tree (ib, data_in);
+         if (item.jftype == IPA_JF_LOAD_AGG)
+           {
+             struct bitpack_d bp;
+             item.value.load_agg.type = stream_read_tree (ib, data_in);
+             item.value.load_agg.offset = streamer_read_uhwi (ib);
+             bp = streamer_read_bitpack (ib);
+             item.value.load_agg.by_ref = bp_unpack_value (&bp, 1);
+           }
+         break;
+       default:
+         fatal_error (UNKNOWN_LOCATION,
+                      "invalid jump function in LTO stream");
+       }
+      if (prevails)
+        jump_func->agg.items->quick_push (item);
     }
 
   struct bitpack_d bp = streamer_read_bitpack (ib);
   bool bits_known = bp_unpack_value (&bp, 1);
   if (bits_known)
     {
-      jump_func->bits.known = true;
-      jump_func->bits.value = streamer_read_widest_int (ib);
-      jump_func->bits.mask = streamer_read_widest_int (ib);
+      widest_int value = streamer_read_widest_int (ib);
+      widest_int mask = streamer_read_widest_int (ib);
+      if (prevails)
+        ipa_set_jfunc_bits (jump_func, value, mask);
     }
   else
-    jump_func->bits.known = false;
+    jump_func->bits = NULL;
 
   struct bitpack_d vr_bp = streamer_read_bitpack (ib);
   bool vr_known = bp_unpack_value (&vr_bp, 1);
   if (vr_known)
     {
-      jump_func->vr_known = true;
-      jump_func->m_vr.type = streamer_read_enum (ib,
-                                                value_range_type,
-                                                VR_LAST);
-      jump_func->m_vr.min = stream_read_tree (ib, data_in);
-      jump_func->m_vr.max = stream_read_tree (ib, data_in);
+      enum value_range_kind type = streamer_read_enum (ib, value_range_kind,
+                                                      VR_LAST);
+      tree min = stream_read_tree (ib, data_in);
+      tree max = stream_read_tree (ib, data_in);
+      if (prevails)
+        ipa_set_jfunc_vr (jump_func, type, min, max);
     }
   else
-    jump_func->vr_known = false;
+    jump_func->m_vr = NULL;
 }
 
 /* Stream out parts of cgraph_indirect_call_info corresponding to CS that are
@@ -4889,7 +4749,7 @@ static void
 ipa_write_indirect_edge_info (struct output_block *ob,
                              struct cgraph_edge *cs)
 {
-  struct cgraph_indirect_call_info *ii = cs->indirect_info;
+  class cgraph_indirect_call_info *ii = cs->indirect_info;
   struct bitpack_d bp;
 
   streamer_write_hwi (ob, ii->param_index);
@@ -4918,11 +4778,12 @@ ipa_write_indirect_edge_info (struct output_block *ob,
    relevant to indirect inlining from IB.  */
 
 static void
-ipa_read_indirect_edge_info (struct lto_input_block *ib,
-                            struct data_in *data_in,
-                            struct cgraph_edge *cs)
+ipa_read_indirect_edge_info (class lto_input_block *ib,
+                            class data_in *data_in,
+                            struct cgraph_edge *cs,
+                            class ipa_node_params *info)
 {
-  struct cgraph_indirect_call_info *ii = cs->indirect_info;
+  class cgraph_indirect_call_info *ii = cs->indirect_info;
   struct bitpack_d bp;
 
   ii->param_index = (int) streamer_read_hwi (ib);
@@ -4943,6 +4804,14 @@ ipa_read_indirect_edge_info (struct lto_input_block *ib,
       ii->otr_type = stream_read_tree (ib, data_in);
       ii->context.stream_in (ib, data_in);
     }
+  if (info && ii->param_index >= 0)
+    {
+      if (ii->polymorphic)
+       ipa_set_param_used_by_polymorphic_call (info,
+                                               ii->param_index , true);
+      ipa_set_param_used_by_indirect_call (info,
+                                          ii->param_index, true);
+    }
 }
 
 /* Stream out NODE info to OB.  */
@@ -4952,7 +4821,7 @@ ipa_write_node_info (struct output_block *ob, struct cgraph_node *node)
 {
   int node_ref;
   lto_symtab_encoder_t encoder;
-  struct ipa_node_params *info = IPA_NODE_REF (node);
+  class ipa_node_params *info = IPA_NODE_REF (node);
   int j;
   struct cgraph_edge *e;
   struct bitpack_d bp;
@@ -4973,10 +4842,19 @@ ipa_write_node_info (struct output_block *ob, struct cgraph_node *node)
     bp_pack_value (&bp, ipa_is_param_used (info, j), 1);
   streamer_write_bitpack (&bp);
   for (j = 0; j < ipa_get_param_count (info); j++)
-    streamer_write_hwi (ob, ipa_get_controlled_uses (info, j));
+    {
+      streamer_write_hwi (ob, ipa_get_controlled_uses (info, j));
+      stream_write_tree (ob, ipa_get_type (info, j), true);
+    }
   for (e = node->callees; e; e = e->next_callee)
     {
-      struct ipa_edge_args *args = IPA_EDGE_REF (e);
+      class ipa_edge_args *args = IPA_EDGE_REF (e);
+
+      if (!args)
+       {
+         streamer_write_uhwi (ob, 0);
+         continue;
+       }
 
       streamer_write_uhwi (ob,
                           ipa_get_cs_argument_count (args) * 2
@@ -4990,87 +4868,121 @@ ipa_write_node_info (struct output_block *ob, struct cgraph_node *node)
     }
   for (e = node->indirect_calls; e; e = e->next_callee)
     {
-      struct ipa_edge_args *args = IPA_EDGE_REF (e);
-
-      streamer_write_uhwi (ob,
-                          ipa_get_cs_argument_count (args) * 2
-                          + (args->polymorphic_call_contexts != NULL));
-      for (j = 0; j < ipa_get_cs_argument_count (args); j++)
+      class ipa_edge_args *args = IPA_EDGE_REF (e);
+      if (!args)
+       streamer_write_uhwi (ob, 0);
+      else
        {
-         ipa_write_jump_function (ob, ipa_get_ith_jump_func (args, j));
-         if (args->polymorphic_call_contexts != NULL)
-           ipa_get_ith_polymorhic_call_context (args, j)->stream_out (ob);
+         streamer_write_uhwi (ob,
+                              ipa_get_cs_argument_count (args) * 2
+                              + (args->polymorphic_call_contexts != NULL));
+         for (j = 0; j < ipa_get_cs_argument_count (args); j++)
+           {
+             ipa_write_jump_function (ob, ipa_get_ith_jump_func (args, j));
+             if (args->polymorphic_call_contexts != NULL)
+               ipa_get_ith_polymorhic_call_context (args, j)->stream_out (ob);
+           }
        }
       ipa_write_indirect_edge_info (ob, e);
     }
 }
 
-/* Stream in NODE info from IB.  */
+/* Stream in edge E from IB.  */
 
 static void
-ipa_read_node_info (struct lto_input_block *ib, struct cgraph_node *node,
-                   struct data_in *data_in)
+ipa_read_edge_info (class lto_input_block *ib,
+                   class data_in *data_in,
+                   struct cgraph_edge *e, bool prevails)
 {
-  struct ipa_node_params *info = IPA_NODE_REF (node);
-  int k;
-  struct cgraph_edge *e;
-  struct bitpack_d bp;
-
-  ipa_alloc_node_params (node, streamer_read_uhwi (ib));
+  int count = streamer_read_uhwi (ib);
+  bool contexts_computed = count & 1;
 
-  for (k = 0; k < ipa_get_param_count (info); k++)
-    info->descriptors[k].move_cost = streamer_read_uhwi (ib);
-    
-  bp = streamer_read_bitpack (ib);
-  if (ipa_get_param_count (info) != 0)
-    info->analysis_done = true;
-  info->node_enqueued = false;
-  for (k = 0; k < ipa_get_param_count (info); k++)
-    ipa_set_param_used (info, k, bp_unpack_value (&bp, 1));
-  for (k = 0; k < ipa_get_param_count (info); k++)
-    ipa_set_controlled_uses (info, k, streamer_read_hwi (ib));
-  for (e = node->callees; e; e = e->next_callee)
+  count /= 2;
+  if (!count)
+    return;
+  if (prevails && e->possibly_call_in_translation_unit_p ())
     {
-      struct ipa_edge_args *args = IPA_EDGE_REF (e);
-      int count = streamer_read_uhwi (ib);
-      bool contexts_computed = count & 1;
-      count /= 2;
-
-      if (!count)
-       continue;
+      class ipa_edge_args *args = IPA_EDGE_REF_GET_CREATE (e);
       vec_safe_grow_cleared (args->jump_functions, count);
       if (contexts_computed)
        vec_safe_grow_cleared (args->polymorphic_call_contexts, count);
-
-      for (k = 0; k < ipa_get_cs_argument_count (args); k++)
+      for (int k = 0; k < count; k++)
        {
          ipa_read_jump_function (ib, ipa_get_ith_jump_func (args, k), e,
-                                 data_in);
+                                 data_in, prevails);
          if (contexts_computed)
-           ipa_get_ith_polymorhic_call_context (args, k)->stream_in (ib, data_in);
+           ipa_get_ith_polymorhic_call_context (args, k)->stream_in
+                                                            (ib, data_in);
        }
     }
-  for (e = node->indirect_calls; e; e = e->next_callee)
+  else
     {
-      struct ipa_edge_args *args = IPA_EDGE_REF (e);
-      int count = streamer_read_uhwi (ib);
-      bool contexts_computed = count & 1;
-      count /= 2;
-
-      if (count)
+      for (int k = 0; k < count; k++)
        {
-         vec_safe_grow_cleared (args->jump_functions, count);
+         struct ipa_jump_func dummy;
+         ipa_read_jump_function (ib, &dummy, e,
+                                 data_in, prevails);
          if (contexts_computed)
-           vec_safe_grow_cleared (args->polymorphic_call_contexts, count);
-          for (k = 0; k < ipa_get_cs_argument_count (args); k++)
            {
-             ipa_read_jump_function (ib, ipa_get_ith_jump_func (args, k), e,
-                                     data_in);
-             if (contexts_computed)
-               ipa_get_ith_polymorhic_call_context (args, k)->stream_in (ib, data_in);
+             class ipa_polymorphic_call_context ctx;
+             ctx.stream_in (ib, data_in);
            }
        }
-      ipa_read_indirect_edge_info (ib, data_in, e);
+    }
+}
+
+/* Stream in NODE info from IB.  */
+
+static void
+ipa_read_node_info (class lto_input_block *ib, struct cgraph_node *node,
+                   class data_in *data_in)
+{
+  int k;
+  struct cgraph_edge *e;
+  struct bitpack_d bp;
+  bool prevails = node->prevailing_p ();
+  class ipa_node_params *info = prevails
+                               ? IPA_NODE_REF_GET_CREATE (node) : NULL;
+
+  int param_count = streamer_read_uhwi (ib);
+  if (prevails)
+    {
+      ipa_alloc_node_params (node, param_count);
+      for (k = 0; k < param_count; k++)
+        (*info->descriptors)[k].move_cost = streamer_read_uhwi (ib);
+      if (ipa_get_param_count (info) != 0)
+       info->analysis_done = true;
+      info->node_enqueued = false;
+    }
+  else
+    for (k = 0; k < param_count; k++)
+      streamer_read_uhwi (ib);
+
+  bp = streamer_read_bitpack (ib);
+  for (k = 0; k < param_count; k++)
+    {
+      bool used = bp_unpack_value (&bp, 1);
+
+      if (prevails)
+        ipa_set_param_used (info, k, used);
+    }
+  for (k = 0; k < param_count; k++)
+    {
+      int nuses = streamer_read_hwi (ib);
+      tree type = stream_read_tree (ib, data_in);
+
+      if (prevails)
+       {
+         ipa_set_controlled_uses (info, k, nuses);
+         (*info->descriptors)[k].decl_or_type = type;
+       }
+    }
+  for (e = node->callees; e; e = e->next_callee)
+    ipa_read_edge_info (ib, data_in, e, prevails);
+  for (e = node->indirect_calls; e; e = e->next_callee)
+    {
+      ipa_read_edge_info (ib, data_in, e, prevails);
+      ipa_read_indirect_edge_info (ib, data_in, e, info);
     }
 }
 
@@ -5085,7 +4997,7 @@ ipa_prop_write_jump_functions (void)
   lto_symtab_encoder_iterator lsei;
   lto_symtab_encoder_t encoder;
 
-  if (!ipa_node_params_sum)
+  if (!ipa_node_params_sum || !ipa_edge_args_sum)
     return;
 
   ob = create_output_block (LTO_section_jump_functions);
@@ -5127,7 +5039,7 @@ ipa_prop_read_section (struct lto_file_decl_data *file_data, const char *data,
   const int cfg_offset = sizeof (struct lto_function_header);
   const int main_offset = cfg_offset + header->cfg_size;
   const int string_offset = main_offset + header->main_size;
-  struct data_in *data_in;
+  class data_in *data_in;
   unsigned int i;
   unsigned int count;
 
@@ -5173,24 +5085,14 @@ ipa_prop_read_jump_functions (void)
   while ((file_data = file_data_vec[j++]))
     {
       size_t len;
-      const char *data = lto_get_section_data (file_data, LTO_section_jump_functions, NULL, &len);
-
+      const char *data
+       = lto_get_summary_section_data (file_data, LTO_section_jump_functions,
+                                       &len);
       if (data)
         ipa_prop_read_section (file_data, data, len);
     }
 }
 
-/* After merging units, we can get mismatch in argument counts.
-   Also decl merging might've rendered parameter lists obsolete.
-   Also compute called_with_variable_arg info.  */
-
-void
-ipa_update_after_lto_read (void)
-{
-  ipa_check_create_node_params ();
-  ipa_check_create_edge_args ();
-}
-
 void
 write_ipcp_transformation_info (output_block *ob, cgraph_node *node)
 {
@@ -5221,7 +5123,7 @@ write_ipcp_transformation_info (output_block *ob, cgraph_node *node)
       streamer_write_bitpack (&bp);
     }
 
-  ipcp_transformation_summary *ts = ipcp_get_transformation_summary (node);
+  ipcp_transformation *ts = ipcp_get_transformation_summary (node);
   if (ts && vec_safe_length (ts->m_vr) > 0)
     {
       count = ts->m_vr->length ();
@@ -5252,14 +5154,14 @@ write_ipcp_transformation_info (output_block *ob, cgraph_node *node)
 
       for (unsigned i = 0; i < count; ++i)
        {
-         const ipa_bitsbits_jfunc = (*ts->bits)[i];
+         const ipa_bits *bits_jfunc = (*ts->bits)[i];
          struct bitpack_d bp = bitpack_create (ob->main_stream);
-         bp_pack_value (&bp, bits_jfunc.known, 1);
+         bp_pack_value (&bp, !!bits_jfunc, 1);
          streamer_write_bitpack (&bp);
-         if (bits_jfunc.known)
+         if (bits_jfunc)
            {
-             streamer_write_widest_int (ob, bits_jfunc.value);
-             streamer_write_widest_int (ob, bits_jfunc.mask);
+             streamer_write_widest_int (ob, bits_jfunc->value);
+             streamer_write_widest_int (ob, bits_jfunc->mask);
            }
        }
     }
@@ -5296,9 +5198,8 @@ read_ipcp_transformation_info (lto_input_block *ib, cgraph_node *node,
   count = streamer_read_uhwi (ib);
   if (count > 0)
     {
-      ipcp_grow_transformations_if_necessary ();
-
-      ipcp_transformation_summary *ts = ipcp_get_transformation_summary (node);
+      ipcp_transformation_initialize ();
+      ipcp_transformation *ts = ipcp_transformation_sum->get_create (node);
       vec_safe_grow_cleared (ts->m_vr, count);
       for (i = 0; i < count; i++)
        {
@@ -5309,7 +5210,7 @@ read_ipcp_transformation_info (lto_input_block *ib, cgraph_node *node,
          parm_vr->known = bp_unpack_value (&bp, 1);
          if (parm_vr->known)
            {
-             parm_vr->type = streamer_read_enum (ib, value_range_type,
+             parm_vr->type = streamer_read_enum (ib, value_range_kind,
                                                  VR_LAST);
              parm_vr->min = streamer_read_wide_int (ib);
              parm_vr->max = streamer_read_wide_int (ib);
@@ -5319,20 +5220,21 @@ read_ipcp_transformation_info (lto_input_block *ib, cgraph_node *node,
   count = streamer_read_uhwi (ib);
   if (count > 0)
     {
-      ipcp_grow_transformations_if_necessary ();
-
-      ipcp_transformation_summary *ts = ipcp_get_transformation_summary (node);
+      ipcp_transformation_initialize ();
+      ipcp_transformation *ts = ipcp_transformation_sum->get_create (node);
       vec_safe_grow_cleared (ts->bits, count);
 
       for (i = 0; i < count; i++)
        {
-         ipa_bits& bits_jfunc = (*ts->bits)[i];
          struct bitpack_d bp = streamer_read_bitpack (ib);
-         bits_jfunc.known = bp_unpack_value (&bp, 1);
-         if (bits_jfunc.known)
+         bool known = bp_unpack_value (&bp, 1);
+         if (known)
            {
-             bits_jfunc.value = streamer_read_widest_int (ib);
-             bits_jfunc.mask = streamer_read_widest_int (ib);
+             const widest_int value = streamer_read_widest_int (ib);
+             const widest_int mask = streamer_read_widest_int (ib);
+             ipa_bits *bits
+               = ipa_get_ipa_bits_for_value (value, mask);
+             (*ts->bits)[i] = bits;
            }
        }
     }
@@ -5387,7 +5289,7 @@ read_replacements_section (struct lto_file_decl_data *file_data,
   const int cfg_offset = sizeof (struct lto_function_header);
   const int main_offset = cfg_offset + header->cfg_size;
   const int string_offset = main_offset + header->main_size;
-  struct data_in *data_in;
+  class data_in *data_in;
   unsigned int i;
   unsigned int count;
 
@@ -5428,9 +5330,9 @@ ipcp_read_transformation_summaries (void)
   while ((file_data = file_data_vec[j++]))
     {
       size_t len;
-      const char *data = lto_get_section_data (file_data,
-                                              LTO_section_ipcp_transform,
-                                              NULL, &len);
+      const char *data
+       = lto_get_summary_section_data (file_data, LTO_section_ipcp_transform,
+                                       &len);
       if (data)
         read_replacements_section (file_data, data, len);
     }
@@ -5444,31 +5346,24 @@ adjust_agg_replacement_values (struct cgraph_node *node,
                               struct ipa_agg_replacement_value *aggval)
 {
   struct ipa_agg_replacement_value *v;
-  int i, c = 0, d = 0, *adj;
 
-  if (!node->clone.combined_args_to_skip)
+  if (!node->clone.param_adjustments)
     return;
 
+  auto_vec<int, 16> new_indices;
+  node->clone.param_adjustments->get_updated_indices (&new_indices);
   for (v = aggval; v; v = v->next)
     {
-      gcc_assert (v->index >= 0);
-      if (c < v->index)
-       c = v->index;
-    }
-  c++;
+      gcc_checking_assert (v->index >= 0);
 
-  adj = XALLOCAVEC (int, c);
-  for (i = 0; i < c; i++)
-    if (bitmap_bit_p (node->clone.combined_args_to_skip, i))
-      {
-       adj[i] = -1;
-       d++;
-      }
-    else
-      adj[i] = i - d;
-
-  for (v = aggval; v; v = v->next)
-    v->index = adj[v->index];
+      if ((unsigned) v->index < new_indices.length ())
+       v->index = new_indices[v->index];
+      else
+       /* This can happen if we know about a constant passed by reference by
+          an argument which is never actually used for anything, let alone
+          loading that constant.  */
+       v->index = -1;
+    }
 }
 
 /* Dominator walker driving the ipcp modification phase.  */
@@ -5477,7 +5372,7 @@ class ipcp_modif_dom_walker : public dom_walker
 {
 public:
   ipcp_modif_dom_walker (struct ipa_func_body_info *fbi,
-                        vec<ipa_param_descriptordescs,
+                        vec<ipa_param_descriptor, va_gc> *descs,
                         struct ipa_agg_replacement_value *av,
                         bool *sc, bool *cc)
     : dom_walker (CDI_DOMINATORS), m_fbi (fbi), m_descriptors (descs),
@@ -5487,7 +5382,7 @@ public:
 
 private:
   struct ipa_func_body_info *m_fbi;
-  vec<ipa_param_descriptorm_descriptors;
+  vec<ipa_param_descriptor, va_gc> *m_descriptors;
   struct ipa_agg_replacement_value *m_aggval;
   bool *m_something_changed, *m_cfg_changed;
 };
@@ -5501,7 +5396,8 @@ ipcp_modif_dom_walker::before_dom_children (basic_block bb)
       struct ipa_agg_replacement_value *v;
       gimple *stmt = gsi_stmt (gsi);
       tree rhs, val, t;
-      HOST_WIDE_INT offset, size;
+      HOST_WIDE_INT offset;
+      poly_int64 size;
       int index;
       bool by_ref, vce;
 
@@ -5517,7 +5413,7 @@ ipcp_modif_dom_walker::before_dom_children (basic_block bb)
        {
          /* V_C_E can do things like convert an array of integers to one
             bigger integer and similar things we do not handle below.  */
-         if (TREE_CODE (rhs) == VIEW_CONVERT_EXPR)
+         if (TREE_CODE (t) == VIEW_CONVERT_EXPR)
            {
              vce = true;
              break;
@@ -5536,7 +5432,8 @@ ipcp_modif_dom_walker::before_dom_children (basic_block bb)
          break;
       if (!v
          || v->by_ref != by_ref
-         || tree_to_shwi (TYPE_SIZE (TREE_TYPE (v->value))) != size)
+         || maybe_ne (tree_to_poly_int64 (TYPE_SIZE (TREE_TYPE (v->value))),
+                      size))
        continue;
 
       gcc_checking_assert (is_gimple_ip_invariant (v->value));
@@ -5552,9 +5449,9 @@ ipcp_modif_dom_walker::before_dom_children (basic_block bb)
              if (dump_file)
                {
                  fprintf (dump_file, "    const ");
-                 print_generic_expr (dump_file, v->value, 0);
+                 print_generic_expr (dump_file, v->value);
                  fprintf (dump_file, "  can't be converted to type of ");
-                 print_generic_expr (dump_file, rhs, 0);
+                 print_generic_expr (dump_file, rhs);
                  fprintf (dump_file, "\n");
                }
              continue;
@@ -5566,7 +5463,7 @@ ipcp_modif_dom_walker::before_dom_children (basic_block bb)
       if (dump_file && (dump_flags & TDF_DETAILS))
        {
          fprintf (dump_file, "Modifying stmt:\n  ");
-         print_gimple_stmt (dump_file, stmt, 0, 0);
+         print_gimple_stmt (dump_file, stmt, 0);
        }
       gimple_assign_set_rhs_from_tree (&gsi, val);
       update_stmt (stmt);
@@ -5574,7 +5471,7 @@ ipcp_modif_dom_walker::before_dom_children (basic_block bb)
       if (dump_file && (dump_flags & TDF_DETAILS))
        {
          fprintf (dump_file, "into:\n  ");
-         print_gimple_stmt (dump_file, stmt, 0, 0);
+         print_gimple_stmt (dump_file, stmt, 0);
          fprintf (dump_file, "\n");
        }
 
@@ -5586,35 +5483,90 @@ ipcp_modif_dom_walker::before_dom_children (basic_block bb)
   return NULL;
 }
 
+/* Return true if we have recorded VALUE and MASK about PARM.
+   Set VALUE and MASk accordingly.  */
+
+bool
+ipcp_get_parm_bits (tree parm, tree *value, widest_int *mask)
+{
+  cgraph_node *cnode = cgraph_node::get (current_function_decl);
+  ipcp_transformation *ts = ipcp_get_transformation_summary (cnode);
+  if (!ts || vec_safe_length (ts->bits) == 0)
+    return false;
+
+  int i = 0;
+  for (tree p = DECL_ARGUMENTS (current_function_decl);
+       p != parm; p = DECL_CHAIN (p))
+    {
+      i++;
+      /* Ignore static chain.  */
+      if (!p)
+       return false;
+    }
+
+  if (cnode->clone.param_adjustments)
+    {
+      i = cnode->clone.param_adjustments->get_original_index (i);
+      if (i < 0)
+       return false;
+    }
+
+  vec<ipa_bits *, va_gc> &bits = *ts->bits;
+  if (!bits[i])
+    return false;
+  *mask = bits[i]->mask;
+  *value = wide_int_to_tree (TREE_TYPE (parm), bits[i]->value);
+  return true;
+}
+
+
 /* Update bits info of formal parameters as described in
-   ipcp_transformation_summary.  */
+   ipcp_transformation.  */
 
 static void
 ipcp_update_bits (struct cgraph_node *node)
 {
-  tree parm = DECL_ARGUMENTS (node->decl);
-  tree next_parm = parm;
-  ipcp_transformation_summary *ts = ipcp_get_transformation_summary (node);
+  ipcp_transformation *ts = ipcp_get_transformation_summary (node);
 
   if (!ts || vec_safe_length (ts->bits) == 0)
     return;
-
-  vec<ipa_bits, va_gc> &bits = *ts->bits;
+  vec<ipa_bits *, va_gc> &bits = *ts->bits;
   unsigned count = bits.length ();
+  if (!count)
+    return;
 
-  for (unsigned i = 0; i < count; ++i, parm = next_parm)
+  auto_vec<int, 16> new_indices;
+  bool need_remapping = false;
+  if (node->clone.param_adjustments)
     {
-      if (node->clone.combined_args_to_skip
-         && bitmap_bit_p (node->clone.combined_args_to_skip, i))
-       continue;
+      node->clone.param_adjustments->get_updated_indices (&new_indices);
+      need_remapping = true;
+    }
+  auto_vec <tree, 16> parm_decls;
+  push_function_arg_decls (&parm_decls, node->decl);
 
+  for (unsigned i = 0; i < count; ++i)
+    {
+      tree parm;
+      if (need_remapping)
+       {
+         if (i >= new_indices.length ())
+           continue;
+         int idx = new_indices[i];
+         if (idx < 0)
+           continue;
+         parm = parm_decls[idx];
+       }
+      else
+       parm = parm_decls[i];
       gcc_checking_assert (parm);
-      next_parm = DECL_CHAIN (parm);
 
-      if (!bits[i].known
-         || !(INTEGRAL_TYPE_P (TREE_TYPE (parm)) || POINTER_TYPE_P (TREE_TYPE (parm)))
+
+      if (!bits[i]
+         || !(INTEGRAL_TYPE_P (TREE_TYPE (parm))
+              || POINTER_TYPE_P (TREE_TYPE (parm)))
          || !is_gimple_reg (parm))
-       continue;       
+       continue;
 
       tree ddef = ssa_default_def (DECL_STRUCT_FUNCTION (node->decl), parm);
       if (!ddef)
@@ -5622,8 +5574,8 @@ ipcp_update_bits (struct cgraph_node *node)
 
       if (dump_file)
        {
-         fprintf (dump_file, "Adjusting mask for param %u to ", i); 
-         print_hex (bits[i].mask, dump_file);
+         fprintf (dump_file, "Adjusting mask for param %u to ", i);
+         print_hex (bits[i]->mask, dump_file);
          fprintf (dump_file, "\n");
        }
 
@@ -5632,14 +5584,14 @@ ipcp_update_bits (struct cgraph_node *node)
          unsigned prec = TYPE_PRECISION (TREE_TYPE (ddef));
          signop sgn = TYPE_SIGN (TREE_TYPE (ddef));
 
-         wide_int nonzero_bits = wide_int::from (bits[i].mask, prec, UNSIGNED)
-                                 | wide_int::from (bits[i].value, prec, sgn);
+         wide_int nonzero_bits = wide_int::from (bits[i]->mask, prec, UNSIGNED)
+                                 | wide_int::from (bits[i]->value, prec, sgn);
          set_nonzero_bits (ddef, nonzero_bits);
        }
       else
        {
-         unsigned tem = bits[i].mask.to_uhwi ();
-         unsigned HOST_WIDE_INT bitpos = bits[i].value.to_uhwi (); 
+         unsigned tem = bits[i]->mask.to_uhwi ();
+         unsigned HOST_WIDE_INT bitpos = bits[i]->value.to_uhwi ();
          unsigned align = tem & -tem;
          unsigned misalign = bitpos & (align - 1);
 
@@ -5677,28 +5629,61 @@ ipcp_update_bits (struct cgraph_node *node)
     }
 }
 
+bool
+ipa_vr::nonzero_p (tree expr_type) const
+{
+  if (type == VR_ANTI_RANGE && wi::eq_p (min, 0) && wi::eq_p (max, 0))
+    return true;
+
+  unsigned prec = TYPE_PRECISION (expr_type);
+  return (type == VR_RANGE
+         && TYPE_UNSIGNED (expr_type)
+         && wi::eq_p (min, wi::one (prec))
+         && wi::eq_p (max, wi::max_value (prec, TYPE_SIGN (expr_type))));
+}
+
 /* Update value range of formal parameters as described in
-   ipcp_transformation_summary.  */
+   ipcp_transformation.  */
 
 static void
 ipcp_update_vr (struct cgraph_node *node)
 {
-  tree fndecl = node->decl;
-  tree parm = DECL_ARGUMENTS (fndecl);
-  tree next_parm = parm;
-  ipcp_transformation_summary *ts = ipcp_get_transformation_summary (node);
+  ipcp_transformation *ts = ipcp_get_transformation_summary (node);
   if (!ts || vec_safe_length (ts->m_vr) == 0)
     return;
   const vec<ipa_vr, va_gc> &vr = *ts->m_vr;
   unsigned count = vr.length ();
+  if (!count)
+    return;
 
-  for (unsigned i = 0; i < count; ++i, parm = next_parm)
+  auto_vec<int, 16> new_indices;
+  bool need_remapping = false;
+  if (node->clone.param_adjustments)
     {
-      if (node->clone.combined_args_to_skip
-         && bitmap_bit_p (node->clone.combined_args_to_skip, i))
-       continue;
+      node->clone.param_adjustments->get_updated_indices (&new_indices);
+      need_remapping = true;
+    }
+  auto_vec <tree, 16> parm_decls;
+  push_function_arg_decls (&parm_decls, node->decl);
+
+  for (unsigned i = 0; i < count; ++i)
+    {
+      tree parm;
+      int remapped_idx;
+      if (need_remapping)
+       {
+         if (i >= new_indices.length ())
+           continue;
+         remapped_idx = new_indices[i];
+         if (remapped_idx < 0)
+           continue;
+       }
+      else
+       remapped_idx = i;
+
+      parm = parm_decls[remapped_idx];
+
       gcc_checking_assert (parm);
-      next_parm = DECL_CHAIN (parm);
       tree ddef = ssa_default_def (DECL_STRUCT_FUNCTION (node->decl), parm);
 
       if (!ddef || !is_gimple_reg (parm))
@@ -5713,7 +5698,8 @@ ipcp_update_vr (struct cgraph_node *node)
            {
              if (dump_file)
                {
-                 fprintf (dump_file, "Setting value range of param %u ", i);
+                 fprintf (dump_file, "Setting value range of param %u "
+                          "(now %i) ", i, remapped_idx);
                  fprintf (dump_file, "%s[",
                           (vr[i].type == VR_ANTI_RANGE) ? "~" : "");
                  print_decs (vr[i].min, dump_file);
@@ -5728,9 +5714,7 @@ ipcp_update_vr (struct cgraph_node *node)
                                                      TYPE_SIGN (type)));
            }
          else if (POINTER_TYPE_P (TREE_TYPE (ddef))
-                  && vr[i].type == VR_ANTI_RANGE
-                  && wi::eq_p (vr[i].min, 0)
-                  && wi::eq_p (vr[i].max, 0))
+                  && vr[i].nonzero_p (TREE_TYPE (ddef)))
            {
              if (dump_file)
                fprintf (dump_file, "Setting nonnull for %u\n", i);
@@ -5745,7 +5729,7 @@ ipcp_update_vr (struct cgraph_node *node)
 unsigned int
 ipcp_transform_function (struct cgraph_node *node)
 {
-  vec<ipa_param_descriptor> descriptors = vNULL;
+  vec<ipa_param_descriptor, va_gc> *descriptors = NULL;
   struct ipa_func_body_info fbi;
   struct ipa_agg_replacement_value *aggval;
   int param_count;
@@ -5755,8 +5739,8 @@ ipcp_transform_function (struct cgraph_node *node)
   gcc_checking_assert (current_function_decl);
 
   if (dump_file)
-    fprintf (dump_file, "Modification phase of node %s/%i\n",
-            node->name (), node->order);
+    fprintf (dump_file, "Modification phase of node %s\n",
+            node->dump_name ());
 
   ipcp_update_bits (node);
   ipcp_update_vr (node);
@@ -5775,10 +5759,10 @@ ipcp_transform_function (struct cgraph_node *node)
   fbi.bb_infos = vNULL;
   fbi.bb_infos.safe_grow_cleared (last_basic_block_for_fn (cfun));
   fbi.param_count = param_count;
-  fbi.aa_walked = 0;
+  fbi.aa_walk_budget = opt_for_fn (node->decl, param_ipa_max_aa_steps);
 
-  descriptors.safe_grow_cleared (param_count);
-  ipa_populate_param_decls (node, descriptors);
+  vec_safe_grow_cleared (descriptors, param_count);
+  ipa_populate_param_decls (node, *descriptors);
   calculate_dominance_info (CDI_DOMINATORS);
   ipcp_modif_dom_walker (&fbi, descriptors, aggval, &something_changed,
                         &cfg_changed).walk (ENTRY_BLOCK_PTR_FOR_FN (cfun));
@@ -5789,16 +5773,29 @@ ipcp_transform_function (struct cgraph_node *node)
     free_ipa_bb_info (bi);
   fbi.bb_infos.release ();
   free_dominance_info (CDI_DOMINATORS);
-  (*ipcp_transformations)[node->uid].agg_values = NULL;
-  (*ipcp_transformations)[node->uid].bits = NULL;
-  (*ipcp_transformations)[node->uid].m_vr = NULL;
 
-  descriptors.release ();
+  ipcp_transformation *s = ipcp_transformation_sum->get (node);
+  s->agg_values = NULL;
+  s->bits = NULL;
+  s->m_vr = NULL;
+
+  vec_free (descriptors);
 
   if (!something_changed)
     return 0;
-  else if (cfg_changed)
-    return TODO_update_ssa_only_virtuals | TODO_cleanup_cfg;
-  else
-    return TODO_update_ssa_only_virtuals;
+
+  if (cfg_changed)
+    delete_unreachable_blocks_update_callgraph (node, false);
+
+  return TODO_update_ssa_only_virtuals;
+}
+
+
+/* Return true if OTHER describes same agg value.  */
+bool
+ipa_agg_value::equal_to (const ipa_agg_value &other)
+{
+  return offset == other.offset
+        && operand_equal_p (value, other.value, 0);
 }
+#include "gt-ipa-prop.h"