]> git.ipfire.org Git - thirdparty/gcc.git/blobdiff - gcc/ipa-prop.c
libgo: update to Go 1.12.2
[thirdparty/gcc.git] / gcc / ipa-prop.c
index c73ffd7b5866015d1e233c7aef1311376c53b526..d86c2f3db5528f5fe3c67e46cecd2f3bb761a212 100644 (file)
@@ -1,5 +1,5 @@
 /* Interprocedural analyses.
-   Copyright (C) 2005-2017 Free Software Foundation, Inc.
+   Copyright (C) 2005-2019 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -52,11 +52,13 @@ along with GCC; see the file COPYING3.  If not see
 #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;
+
+function_summary <ipcp_transformation *> *ipcp_transformation_sum = NULL;
+
 /* Edge summary for IPA-CP edge information.  */
 ipa_edge_args_sum_t *ipa_edge_args_sum;
 
@@ -105,42 +107,42 @@ 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 *>
+struct ipa_vr_ggc_hash_traits : public ggc_cache_remove <value_range_base *>
 {
-  typedef value_range *value_type;
-  typedef value_range *compare_type;
+  typedef value_range_base *value_type;
+  typedef value_range_base *compare_type;
   static hashval_t
-  hash (const value_range *p)
-  {
-    gcc_checking_assert (!p->equiv);
-    hashval_t t = (hashval_t) p->type;
-    t = iterative_hash_expr (p->min, t);
-    return iterative_hash_expr (p->max, t);
-  }
+  hash (const value_range_base *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)
+  equal (const value_range_base *a, const value_range_base *b)
     {
-      return a->type == b->type && a->min == b->min && a->max == b->max;
+      return a->equal_p (*b);
     }
   static void
-  mark_empty (value_range *&p)
+  mark_empty (value_range_base *&p)
     {
       p = NULL;
     }
   static bool
-  is_empty (const value_range *p)
+  is_empty (const value_range_base *p)
     {
       return p == NULL;
     }
   static bool
-  is_deleted (const value_range *p)
+  is_deleted (const value_range_base *p)
     {
-      return p == reinterpret_cast<const value_range *> (1);
+      return p == reinterpret_cast<const value_range_base *> (1);
     }
   static void
-  mark_deleted (value_range *&p)
+  mark_deleted (value_range_base *&p)
     {
-      p = reinterpret_cast<value_range *> (1);
+      p = reinterpret_cast<value_range_base *> (1);
     }
 };
 
@@ -396,10 +398,10 @@ ipa_print_node_jump_functions_for_edge (FILE *f, struct cgraph_edge *cs)
        {
          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
@@ -652,7 +654,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.  */
        }
@@ -685,14 +687,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;
@@ -745,13 +747,13 @@ 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,
+                                      struct ipa_jump_func *jfunc,
                                       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
@@ -779,9 +781,11 @@ 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);
@@ -795,8 +799,9 @@ detect_type_change_from_memory_writes (tree arg, tree base, tree comp_type,
    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, struct ipa_jump_func *jfunc,
+                   HOST_WIDE_INT offset)
 {
   if (!flag_devirtualize)
     return false;
@@ -806,7 +811,7 @@ 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,
+  return detect_type_change_from_memory_writes (fbi, arg, base, comp_type,
                                                call, jfunc, offset);
 }
 
@@ -815,7 +820,7 @@ 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,
+detect_type_change_ssa (ipa_func_body_info *fbi, tree arg, tree comp_type,
                        gcall *call, struct ipa_jump_func *jfunc)
 {
   gcc_checking_assert (TREE_CODE (arg) == SSA_NAME);
@@ -829,7 +834,7 @@ 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,
+  return detect_type_change_from_memory_writes (fbi, arg, arg, comp_type,
                                                call, jfunc, 0);
 }
 
@@ -845,16 +850,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.  */
 
@@ -921,28 +916,24 @@ 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;
@@ -987,29 +978,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;
 }
@@ -1029,8 +1015,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,
@@ -1041,8 +1026,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;
@@ -1071,12 +1063,11 @@ ipa_load_from_parm_agg (struct ipa_func_body_info *fbi,
                        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))
@@ -1204,7 +1195,7 @@ compute_complex_assign_jump_func (struct ipa_func_body_info *fbi,
                                  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;
@@ -1267,13 +1258,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)
@@ -1301,7 +1292,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;
 
@@ -1313,13 +1304,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
@@ -1327,7 +1317,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;
 }
@@ -1570,7 +1560,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;
@@ -1581,15 +1572,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))
            {
@@ -1604,18 +1592,15 @@ 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);
@@ -1631,7 +1616,7 @@ determine_locally_known_aggregate_parts (gcall *call, tree arg,
     {
       struct ipa_known_agg_contents_list *n, **p;
       gimple *stmt = gsi_stmt (gsi);
-      HOST_WIDE_INT lhs_offset, lhs_size, lhs_max_size;
+      HOST_WIDE_INT lhs_offset, lhs_size;
       tree lhs, rhs, lhs_base;
       bool reverse;
 
@@ -1647,10 +1632,9 @@ determine_locally_known_aggregate_parts (gcall *call, tree arg,
          || 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)
+      lhs_base = get_ref_base_and_extent_hwi (lhs, &lhs_offset,
+                                             &lhs_size, &reverse);
+      if (!lhs_base)
        break;
 
       if (check_ref)
@@ -1777,14 +1761,14 @@ ipa_set_jfunc_bits (ipa_jump_func *jf, const widest_int &value,
 /* 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)
+static value_range_base *
+ipa_get_value_range (value_range_base *tmp)
 {
-  value_range **slot = ipa_vr_hash_table->find_slot (tmp, INSERT);
+  value_range_base **slot = ipa_vr_hash_table->find_slot (tmp, INSERT);
   if (*slot)
     return *slot;
 
-  value_range *vr = ggc_alloc<value_range> ();
+  value_range_base *vr = ggc_alloc<value_range_base> ();
   *vr = *tmp;
   *slot = vr;
 
@@ -1795,14 +1779,10 @@ ipa_get_value_range (value_range *tmp)
    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_type type, tree min, tree max)
+static value_range_base *
+ipa_get_value_range (enum value_range_kind type, tree min, tree max)
 {
-  value_range tmp;
-  tmp.type = type;
-  tmp.min = min;
-  tmp.max = max;
-  tmp.equiv = NULL;
+  value_range_base tmp (type, min, max);
   return ipa_get_value_range (&tmp);
 }
 
@@ -1811,7 +1791,7 @@ ipa_get_value_range (enum value_range_type type, tree min, tree max)
    same value_range structures.  */
 
 static void
-ipa_set_jfunc_vr (ipa_jump_func *jf, enum value_range_type type,
+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);
@@ -1821,7 +1801,7 @@ ipa_set_jfunc_vr (ipa_jump_func *jf, enum value_range_type type,
    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)
+ipa_set_jfunc_vr (ipa_jump_func *jf, value_range_base *tmp)
 {
   jf->m_vr = ipa_get_value_range (tmp);
 }
@@ -1862,7 +1842,8 @@ ipa_compute_jump_functions_for_edge (struct ipa_func_body_info *fbi,
          struct 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;
@@ -1891,22 +1872,19 @@ ipa_compute_jump_functions_for_edge (struct ipa_func_body_info *fbi,
       else
        {
          wide_int min, max;
-         value_range_type type;
+         value_range_kind type;
          if (TREE_CODE (arg) == SSA_NAME
              && param_type
              && (type = get_range_info (arg, &min, &max))
              && (type == VR_RANGE || type == VR_ANTI_RANGE))
            {
-             value_range tmpvr,resvr;
-
-             tmpvr.type = type;
-             tmpvr.min = wide_int_to_tree (TREE_TYPE (arg), min);
-             tmpvr.max = wide_int_to_tree (TREE_TYPE (arg), max);
-             tmpvr.equiv = NULL;
-             memset (&resvr, 0, sizeof (resvr));
+             value_range_base resvr;
+             value_range_base tmpvr (type,
+                                     wide_int_to_tree (TREE_TYPE (arg), min),
+                                     wide_int_to_tree (TREE_TYPE (arg), max));
              extract_range_from_unary_expr (&resvr, NOP_EXPR, param_type,
                                             &tmpvr, TREE_TYPE (arg));
-             if (resvr.type == VR_RANGE || resvr.type == VR_ANTI_RANGE)
+             if (!resvr.undefined_p () && !resvr.varying_p ())
                ipa_set_jfunc_vr (jfunc, &resvr);
              else
                gcc_assert (!jfunc->m_vr);
@@ -1931,9 +1909,9 @@ ipa_compute_jump_functions_for_edge (struct ipa_func_body_info *fbi,
          unsigned align;
 
          get_pointer_alignment_1 (arg, &align, &bitpos);
-         widest_int mask
-           = wi::mask<widest_int>(TYPE_PRECISION (TREE_TYPE (arg)), false)
-           .and_not (align / BITS_PER_UNIT - 1);
+         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);
        }
@@ -1985,7 +1963,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.
@@ -2338,7 +2316,7 @@ ipa_analyze_virtual_call_uses (struct ipa_func_body_info *fbi,
       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),
+      if (detect_type_change_ssa (fbi, obj, obj_type_ref_class (target),
                                  call, &jfunc))
        return;
     }
@@ -2354,7 +2332,7 @@ 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),
+      if (detect_type_change (fbi, obj, expr, obj_type_ref_class (target),
                              call, &jfunc, anc_offset))
        return;
     }
@@ -2402,7 +2380,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;
     }
 
@@ -2602,7 +2581,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 = PARAM_VALUE (PARAM_IPA_MAX_AA_STEPS);
 
   for (struct cgraph_edge *cs = node->callees; cs; cs = cs->next_callee)
     {
@@ -2826,7 +2805,6 @@ ipa_make_edge_direct_to_target (struct cgraph_edge *ie, tree target,
                                bool speculative)
 {
   struct cgraph_node *callee;
-  struct ipa_call_summary *es = ipa_call_summaries->get (ie);
   bool unreachable = false;
 
   if (TREE_CODE (target) == ADDR_EXPR)
@@ -2850,8 +2828,7 @@ 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,
                                   "discovered direct call non-invariant %s\n",
                                   ie->caller->dump_name ());
                }
@@ -2861,8 +2838,7 @@ 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,
                               "discovered direct call to non-function in %s, "
                               "making it __builtin_unreachable\n",
                               ie->caller->dump_name ());
@@ -2892,7 +2868,7 @@ 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 -> %s) but can not refer to it. Giving up.\n",
+                    "(%s -> %s) but cannot refer to it. Giving up.\n",
                     ie->caller->dump_name (),
                     ie->callee->dump_name ());
          return NULL;
@@ -2931,7 +2907,7 @@ 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);
 
@@ -2950,9 +2926,7 @@ 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 ());
     }
@@ -2964,7 +2938,7 @@ ipa_make_edge_direct_to_target (struct cgraph_edge *ie, tree target,
         for direct call (adjusted by inline_edge_duplication_hook).  */
       if (ie == orig)
        {
-         es = ipa_call_summaries->get (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
@@ -2982,7 +2956,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.apply_scale (8, 10), ie->frequency * 8 / 10);
+            (callee, ie->count.apply_scale (8, 10));
     }
 
   return ie;
@@ -3013,7 +2987,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));
@@ -3022,6 +2999,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;
@@ -3202,19 +3181,20 @@ 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.
+   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_INFO is the node 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_jump_func *jfunc, tree target_type,
                                  struct 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;
@@ -3392,7 +3372,7 @@ update_indirect_edges_after_inlining (struct cgraph_edge *cs,
 {
   struct ipa_edge_args *top;
   struct cgraph_edge *ie, *next_ie, *new_direct_edge;
-  struct ipa_node_params *new_root_info;
+  struct ipa_node_params *new_root_info, *inlined_node_info;
   bool res = false;
 
   ipa_check_create_edge_args ();
@@ -3400,6 +3380,7 @@ update_indirect_edges_after_inlining (struct cgraph_edge *cs,
   new_root_info = IPA_NODE_REF (cs->caller->global.inlined_to
                                ? cs->caller->global.inlined_to
                                : cs->caller);
+  inlined_node_info = IPA_NODE_REF (cs->callee->function_symbol ());
 
   for (ie = node->indirect_calls; ie; ie = next_ie)
     {
@@ -3440,8 +3421,13 @@ update_indirect_edges_after_inlining (struct cgraph_edge *cs,
          new_direct_edge = try_make_edge_direct_virtual_call (ie, jfunc, ctx);
        }
       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_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)
@@ -3704,16 +3690,6 @@ ipa_check_create_edge_args (void)
     ipa_vr_hash_table = hash_table<ipa_vr_ggc_hash_traits>::create_ggc (37);
 }
 
-/* Frees all dynamically allocated structures that the argument info points
-   to.  */
-
-void
-ipa_free_edge_args_substructures (struct ipa_edge_args *args)
-{
-  vec_free (args->jump_functions);
-  memset (args, 0, sizeof (*args));
-}
-
 /* Free all ipa_edge structures.  */
 
 void
@@ -3735,19 +3711,18 @@ ipa_free_all_node_params (void)
   ipa_node_params_sum = NULL;
 }
 
-/* Grow ipcp_transformations if necessary.  Also allocate any necessary hash
+/* Initialize IPA CP transformation summary and also allocate any necessary hash
    tables if they do not already exist.  */
 
 void
-ipcp_grow_transformations_if_necessary (void)
+ipcp_transformation_initialize (void)
 {
-  if (vec_safe_length (ipcp_transformations)
-      <= (unsigned) symtab->cgraph_max_uid)
-    vec_safe_grow_cleared (ipcp_transformations, symtab->cgraph_max_uid + 1);
   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);
 }
 
 /* Set the aggregate replacements of NODE to be AGGVALS.  */
@@ -3756,8 +3731,9 @@ 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.  Adjust reference
@@ -3921,15 +3897,14 @@ 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);
+  ipcp_transformation *src_trans = ipcp_get_transformation_summary (src);
 
   if (src_trans)
     {
-      ipcp_grow_transformations_if_necessary ();
-      src_trans = ipcp_get_transformation_summary (src);
-      ipcp_transformation_summary *dst_trans
-       = ipcp_get_transformation_summary (dst);
+      ipcp_transformation_initialize ();
+      src_trans = ipcp_transformation_sum->get_create (src);
+      ipcp_transformation *dst_trans
+       = ipcp_transformation_sum->get_create (dst);
 
       dst_trans->bits = vec_safe_copy (src_trans->bits);
 
@@ -4045,730 +4020,6 @@ ipa_print_all_params (FILE * f)
     ipa_print_node_params (f, node);
 }
 
-/* Return a heap allocated vector containing formal parameters of FNDECL.  */
-
-vec<tree> 
-ipa_get_vector_of_formal_parms (tree fndecl)
-{
-  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;
-}
-
-/* Return a heap allocated vector containing types of formal parameters of
-   function type FNTYPE.  */
-
-vec<tree>
-ipa_get_vector_of_formal_parm_types (tree fntype)
-{
-  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.  */
-
-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);
-    }
-
-  int len = adjustments.length ();
-  tree *link = &DECL_ARGUMENTS (fndecl);
-  tree new_arg_types = NULL;
-  for (int i = 0; i < len; i++)
-    {
-      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)
-       {
-         if (care_for_types)
-           new_arg_types = tree_cons (NULL_TREE, otypes[adj->base_index],
-                                      new_arg_types);
-         *link = parm;
-         link = &DECL_CHAIN (parm);
-       }
-      else if (adj->op != IPA_PARM_OP_REMOVE)
-       {
-         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)
-                 && TYPE_MODE (ptype) != BLKmode)
-               {
-                 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);
-       }
-    }
-
-  *link = NULL_TREE;
-
-  tree new_reversed = NULL;
-  if (care_for_types)
-    {
-      new_reversed = nreverse (new_arg_types);
-      if (last_parm_void)
-       {
-         if (new_reversed)
-           TREE_CHAIN (new_arg_types) = void_list_node;
-         else
-           new_reversed = void_list_node;
-       }
-    }
-
-  /* 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))
-    {
-      new_type = build_distinct_type_copy (orig_type);
-      TYPE_ARG_TYPES (new_type) = new_reversed;
-    }
-  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);
-    }
-
-  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);
-      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);
-      fprintf (dump_file, " with ");
-      print_generic_expr (dump_file, src);
-      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]);
-      if (adj->base)
-       {
-         fprintf (file, ", base: ");
-         print_generic_expr (file, adj->base);
-       }
-      if (adj->new_decl)
-       {
-         fprintf (file, ", new_decl: ");
-         print_generic_expr (file, adj->new_decl);
-       }
-      if (adj->new_ssa_base)
-       {
-         fprintf (file, ", new_ssa_base: ");
-         print_generic_expr (file, adj->new_ssa_base);
-       }
-
-      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
@@ -4795,8 +4046,15 @@ ipa_write_jump_function (struct output_block *ob,
   struct ipa_agg_jf_item *item;
   struct bitpack_d bp;
   int i, count;
+  int flag = 0;
 
-  streamer_write_uhwi (ob, jump_func->type);
+  /* 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;
+
+  streamer_write_uhwi (ob, jump_func->type * 2 + flag);
   switch (jump_func->type)
     {
     case IPA_JF_UNKNOWN:
@@ -4804,7 +4062,10 @@ ipa_write_jump_function (struct output_block *ob,
     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);
+      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);
@@ -4861,9 +4122,9 @@ ipa_write_jump_function (struct output_block *ob,
   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);
     }
 }
 
@@ -4873,20 +4134,28 @@ static void
 ipa_read_jump_function (struct lto_input_block *ib,
                        struct ipa_jump_func *jump_func,
                        struct cgraph_edge *cs,
-                       struct data_in *data_in)
+                       struct 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);
@@ -4919,10 +4188,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);
@@ -4933,7 +4205,8 @@ ipa_read_jump_function (struct lto_input_block *ib,
       struct ipa_agg_jf_item item;
       item.offset = streamer_read_uhwi (ib);
       item.value = stream_read_tree (ib, data_in);
-      jump_func->agg.items->quick_push (item);
+      if (prevails)
+        jump_func->agg.items->quick_push (item);
     }
 
   struct bitpack_d bp = streamer_read_bitpack (ib);
@@ -4942,7 +4215,8 @@ ipa_read_jump_function (struct lto_input_block *ib,
     {
       widest_int value = streamer_read_widest_int (ib);
       widest_int mask = streamer_read_widest_int (ib);
-      ipa_set_jfunc_bits (jump_func, value, mask);
+      if (prevails)
+        ipa_set_jfunc_bits (jump_func, value, mask);
     }
   else
     jump_func->bits = NULL;
@@ -4951,11 +4225,12 @@ ipa_read_jump_function (struct lto_input_block *ib,
   bool vr_known = bp_unpack_value (&vr_bp, 1);
   if (vr_known)
     {
-      enum value_range_type type = streamer_read_enum (ib, value_range_type,
+      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);
-      ipa_set_jfunc_vr (jump_func, type, min, max);
+      if (prevails)
+        ipa_set_jfunc_vr (jump_func, type, min, max);
     }
   else
     jump_func->m_vr = NULL;
@@ -5087,74 +4362,100 @@ ipa_write_node_info (struct output_block *ob, struct cgraph_node *node)
     }
 }
 
+/* Stream in edge E from IB.  */
+
+static void
+ipa_read_edge_info (struct lto_input_block *ib,
+                   struct data_in *data_in,
+                   struct cgraph_edge *e, bool prevails)
+{
+  int count = streamer_read_uhwi (ib);
+  bool contexts_computed = count & 1;
+
+  count /= 2;
+  if (!count)
+    return;
+  if (prevails && e->possibly_call_in_translation_unit_p ())
+    {
+      struct ipa_edge_args *args = IPA_EDGE_REF (e);
+      vec_safe_grow_cleared (args->jump_functions, count);
+      if (contexts_computed)
+       vec_safe_grow_cleared (args->polymorphic_call_contexts, count);
+      for (int k = 0; k < count; k++)
+       {
+         ipa_read_jump_function (ib, ipa_get_ith_jump_func (args, k), e,
+                                 data_in, prevails);
+         if (contexts_computed)
+           ipa_get_ith_polymorhic_call_context (args, k)->stream_in
+                                                            (ib, data_in);
+       }
+    }
+  else
+    {
+      for (int k = 0; k < count; k++)
+       {
+         struct ipa_jump_func dummy;
+         ipa_read_jump_function (ib, &dummy, e,
+                                 data_in, prevails);
+         if (contexts_computed)
+           {
+             struct ipa_polymorphic_call_context ctx;
+             ctx.stream_in (ib, data_in);
+           }
+       }
+    }
+}
+
 /* Stream in NODE info from IB.  */
 
 static void
 ipa_read_node_info (struct lto_input_block *ib, struct cgraph_node *node,
                    struct data_in *data_in)
 {
-  struct ipa_node_params *info = IPA_NODE_REF (node);
   int k;
   struct cgraph_edge *e;
   struct bitpack_d bp;
+  bool prevails = node->prevailing_p ();
+  struct ipa_node_params *info = prevails ? IPA_NODE_REF (node) : NULL;
 
-  ipa_alloc_node_params (node, streamer_read_uhwi (ib));
-
-  for (k = 0; k < ipa_get_param_count (info); k++)
-    (*info->descriptors)[k].move_cost = streamer_read_uhwi (ib);
+  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);
-  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++)
+  for (k = 0; k < param_count; k++)
     {
-      ipa_set_controlled_uses (info, k, streamer_read_hwi (ib));
-      (*info->descriptors)[k].decl_or_type = stream_read_tree (ib, data_in);
+      bool used = bp_unpack_value (&bp, 1);
+
+      if (prevails)
+        ipa_set_param_used (info, k, used);
     }
-  for (e = node->callees; e; e = e->next_callee)
+  for (k = 0; k < param_count; k++)
     {
-      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;
-      vec_safe_grow_cleared (args->jump_functions, count);
-      if (contexts_computed)
-       vec_safe_grow_cleared (args->polymorphic_call_contexts, count);
+      int nuses = streamer_read_hwi (ib);
+      tree type = stream_read_tree (ib, data_in);
 
-      for (k = 0; k < ipa_get_cs_argument_count (args); k++)
+      if (prevails)
        {
-         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);
+         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)
     {
-      struct ipa_edge_args *args = IPA_EDGE_REF (e);
-      int count = streamer_read_uhwi (ib);
-      bool contexts_computed = count & 1;
-      count /= 2;
-
-      if (count)
-       {
-         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++)
-           {
-             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);
-           }
-       }
+      ipa_read_edge_info (ib, data_in, e, prevails);
       ipa_read_indirect_edge_info (ib, data_in, e);
     }
 }
@@ -5295,7 +4596,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 ();
@@ -5370,9 +4671,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++)
        {
@@ -5383,7 +4683,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);
@@ -5393,9 +4693,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->bits, count);
 
       for (i = 0; i < count; i++)
@@ -5662,14 +4961,14 @@ ipcp_modif_dom_walker::before_dom_children (basic_block bb)
 }
 
 /* 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;
@@ -5754,7 +5053,7 @@ ipcp_update_bits (struct cgraph_node *node)
 }
 
 /* Update value range of formal parameters as described in
-   ipcp_transformation_summary.  */
+   ipcp_transformation.  */
 
 static void
 ipcp_update_vr (struct cgraph_node *node)
@@ -5762,7 +5061,7 @@ 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;
@@ -5851,7 +5150,7 @@ 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 = PARAM_VALUE (PARAM_IPA_MAX_AA_STEPS);
 
   vec_safe_grow_cleared (descriptors, param_count);
   ipa_populate_param_decls (node, *descriptors);
@@ -5865,18 +5164,21 @@ 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;
+
+  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;
 }
 
 #include "gt-ipa-prop.h"