re PR target/54061 (gcc.c-torture/compile/mipscop-*.c ICEs with -g)
[gcc.git] / gcc / ipa-prop.c
index 3fdebc1f2c54fa1b475d16989fc8723db8a91cd9..55bd372e0a848b09a1b8f7b603d95cbba96a9a0e 100644 (file)
@@ -1,5 +1,5 @@
 /* Interprocedural analyses.
 /* Interprocedural analyses.
-   Copyright (C) 2005, 2007, 2008, 2009, 2010
+   Copyright (C) 2005, 2007, 2008, 2009, 2010, 2011, 2012
    Free Software Foundation, Inc.
 
 This file is part of GCC.
    Free Software Foundation, Inc.
 
 This file is part of GCC.
@@ -30,133 +30,82 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-flow.h"
 #include "tree-pass.h"
 #include "tree-inline.h"
 #include "tree-flow.h"
 #include "tree-pass.h"
 #include "tree-inline.h"
+#include "ipa-inline.h"
 #include "gimple.h"
 #include "flags.h"
 #include "gimple.h"
 #include "flags.h"
-#include "timevar.h"
-#include "flags.h"
 #include "diagnostic.h"
 #include "diagnostic.h"
-#include "tree-pretty-print.h"
 #include "gimple-pretty-print.h"
 #include "lto-streamer.h"
 #include "gimple-pretty-print.h"
 #include "lto-streamer.h"
-
+#include "data-streamer.h"
+#include "tree-streamer.h"
+#include "params.h"
 
 /* Intermediate information about a parameter that is only useful during the
    run of ipa_analyze_node and is not kept afterwards.  */
 
 struct param_analysis_info
 {
 
 /* Intermediate information about a parameter that is only useful during the
    run of ipa_analyze_node and is not kept afterwards.  */
 
 struct param_analysis_info
 {
-  bool modified;
-  bitmap visited_statements;
+  bool parm_modified, ref_modified, pt_modified;
+  bitmap parm_visited_statements, pt_visited_statements;
 };
 
 /* Vector where the parameter infos are actually stored. */
 };
 
 /* Vector where the parameter infos are actually stored. */
-VEC (ipa_node_params_t, heap) *ipa_node_params_vector;
+vec<ipa_node_params_t> ipa_node_params_vector;
+/* Vector of known aggregate values in cloned nodes.  */
+vec<ipa_agg_replacement_value_p, va_gc> *ipa_node_agg_replacements;
 /* Vector where the parameter infos are actually stored. */
 /* Vector where the parameter infos are actually stored. */
-VEC (ipa_edge_args_t, gc) *ipa_edge_args_vector;
-
-/* Bitmap with all UIDs of call graph edges that have been already processed
-   by indirect inlining.  */
-static bitmap iinlining_processed_edges;
+vec<ipa_edge_args_t, va_gc> *ipa_edge_args_vector;
 
 /* Holders of ipa cgraph hooks: */
 static struct cgraph_edge_hook_list *edge_removal_hook_holder;
 static struct cgraph_node_hook_list *node_removal_hook_holder;
 static struct cgraph_2edge_hook_list *edge_duplication_hook_holder;
 static struct cgraph_2node_hook_list *node_duplication_hook_holder;
 
 /* Holders of ipa cgraph hooks: */
 static struct cgraph_edge_hook_list *edge_removal_hook_holder;
 static struct cgraph_node_hook_list *node_removal_hook_holder;
 static struct cgraph_2edge_hook_list *edge_duplication_hook_holder;
 static struct cgraph_2node_hook_list *node_duplication_hook_holder;
-
-/* Add cgraph NODE described by INFO to the worklist WL regardless of whether
-   it is in one or not.  It should almost never be used directly, as opposed to
-   ipa_push_func_to_list.  */
-
-void
-ipa_push_func_to_list_1 (struct ipa_func_list **wl,
-                        struct cgraph_node *node,
-                        struct ipa_node_params *info)
-{
-  struct ipa_func_list *temp;
-
-  info->node_enqueued = 1;
-  temp = XCNEW (struct ipa_func_list);
-  temp->node = node;
-  temp->next = *wl;
-  *wl = temp;
-}
-
-/* Initialize worklist to contain all functions.  */
-
-struct ipa_func_list *
-ipa_init_func_list (void)
-{
-  struct cgraph_node *node;
-  struct ipa_func_list * wl;
-
-  wl = NULL;
-  for (node = cgraph_nodes; node; node = node->next)
-    if (node->analyzed)
-      {
-       struct ipa_node_params *info = IPA_NODE_REF (node);
-       /* Unreachable nodes should have been eliminated before ipcp and
-          inlining.  */
-       gcc_assert (node->needed || node->reachable);
-       ipa_push_func_to_list_1 (&wl, node, info);
-      }
-
-  return wl;
-}
-
-/* Remove a function from the worklist WL and return it.  */
-
-struct cgraph_node *
-ipa_pop_func_from_list (struct ipa_func_list **wl)
-{
-  struct ipa_node_params *info;
-  struct ipa_func_list *first;
-  struct cgraph_node *node;
-
-  first = *wl;
-  *wl = (*wl)->next;
-  node = first->node;
-  free (first);
-
-  info = IPA_NODE_REF (node);
-  info->node_enqueued = 0;
-  return node;
-}
+static struct cgraph_node_hook_list *function_insertion_hook_holder;
 
 /* Return index of the formal whose tree is PTREE in function which corresponds
    to INFO.  */
 
 static int
 
 /* Return index of the formal whose tree is PTREE in function which corresponds
    to INFO.  */
 
 static int
-ipa_get_param_decl_index (struct ipa_node_params *info, tree ptree)
+ipa_get_param_decl_index_1 (vec<ipa_param_descriptor_t> descriptors, tree ptree)
 {
   int i, count;
 
 {
   int i, count;
 
-  count = ipa_get_param_count (info);
+  count = descriptors.length ();
   for (i = 0; i < count; i++)
   for (i = 0; i < count; i++)
-    if (ipa_get_param(info, i) == ptree)
+    if (descriptors[i].decl == ptree)
       return i;
 
   return -1;
 }
 
       return i;
 
   return -1;
 }
 
-/* Populate the param_decl field in parameter descriptors of INFO that
-   corresponds to NODE.  */
+/* Return index of the formal whose tree is PTREE in function which corresponds
+   to INFO.  */
+
+int
+ipa_get_param_decl_index (struct ipa_node_params *info, tree ptree)
+{
+  return ipa_get_param_decl_index_1 (info->descriptors, ptree);
+}
+
+/* Populate the param_decl field in parameter DESCRIPTORS that correspond to
+   NODE.  */
 
 static void
 ipa_populate_param_decls (struct cgraph_node *node,
 
 static void
 ipa_populate_param_decls (struct cgraph_node *node,
-                         struct ipa_node_params *info)
+                         vec<ipa_param_descriptor_t> &descriptors)
 {
   tree fndecl;
   tree fnargs;
   tree parm;
   int param_num;
 
 {
   tree fndecl;
   tree fnargs;
   tree parm;
   int param_num;
 
-  fndecl = node->decl;
+  fndecl = node->symbol.decl;
   fnargs = DECL_ARGUMENTS (fndecl);
   param_num = 0;
   for (parm = fnargs; parm; parm = DECL_CHAIN (parm))
     {
   fnargs = DECL_ARGUMENTS (fndecl);
   param_num = 0;
   for (parm = fnargs; parm; parm = DECL_CHAIN (parm))
     {
-      info->params[param_num].decl = parm;
+      descriptors[param_num].decl = parm;
       param_num++;
     }
 }
       param_num++;
     }
 }
@@ -164,7 +113,7 @@ ipa_populate_param_decls (struct cgraph_node *node,
 /* Return how many formal parameters FNDECL has.  */
 
 static inline int
 /* Return how many formal parameters FNDECL has.  */
 
 static inline int
-count_formal_params_1 (tree fndecl)
+count_formal_params (tree fndecl)
 {
   tree parm;
   int count = 0;
 {
   tree parm;
   int count = 0;
@@ -175,19 +124,6 @@ count_formal_params_1 (tree fndecl)
   return count;
 }
 
   return count;
 }
 
-/* Count number of formal parameters in NOTE. Store the result to the
-   appropriate field of INFO.  */
-
-static void
-ipa_count_formal_params (struct cgraph_node *node,
-                        struct ipa_node_params *info)
-{
-  int param_num;
-
-  param_num = count_formal_params_1 (node->decl);
-  ipa_set_param_count (info, param_num);
-}
-
 /* Initialize the ipa_node_params structure associated with NODE by counting
    the function parameters, creating the descriptors and populating their
    param_decls.  */
 /* Initialize the ipa_node_params structure associated with NODE by counting
    the function parameters, creating the descriptors and populating their
    param_decls.  */
@@ -197,32 +133,17 @@ ipa_initialize_node_params (struct cgraph_node *node)
 {
   struct ipa_node_params *info = IPA_NODE_REF (node);
 
 {
   struct ipa_node_params *info = IPA_NODE_REF (node);
 
-  if (!info->params)
+  if (!info->descriptors.exists ())
     {
     {
-      ipa_count_formal_params (node, info);
-      info->params = XCNEWVEC (struct ipa_param_descriptor,
-                                   ipa_get_param_count (info));
-      ipa_populate_param_decls (node, info);
-    }
-}
+      int param_count;
 
 
-/* Count number of arguments callsite CS has and store it in
-   ipa_edge_args structure corresponding to this callsite.  */
-
-static void
-ipa_count_arguments (struct cgraph_edge *cs)
-{
-  gimple stmt;
-  int arg_num;
-
-  stmt = cs->call_stmt;
-  gcc_assert (is_gimple_call (stmt));
-  arg_num = gimple_call_num_args (stmt);
-  if (VEC_length (ipa_edge_args_t, ipa_edge_args_vector)
-      <= (unsigned) cgraph_edge_max_uid)
-    VEC_safe_grow_cleared (ipa_edge_args_t, gc,
-                          ipa_edge_args_vector, cgraph_edge_max_uid + 1);
-  ipa_set_cs_argument_count (IPA_EDGE_REF (cs), arg_num);
+      param_count = count_formal_params (node->symbol.decl);
+      if (param_count)
+       {
+         info->descriptors.safe_grow_cleared (param_count);
+         ipa_populate_param_decls (node, info->descriptors);
+       }
+    }
 }
 
 /* Print the jump functions associated with call graph edge CS to file F.  */
 }
 
 /* Print the jump functions associated with call graph edge CS to file F.  */
@@ -246,10 +167,12 @@ ipa_print_node_jump_functions_for_edge (FILE *f, struct cgraph_edge *cs)
        fprintf (f, "UNKNOWN\n");
       else if (type == IPA_JF_KNOWN_TYPE)
        {
        fprintf (f, "UNKNOWN\n");
       else if (type == IPA_JF_KNOWN_TYPE)
        {
-         tree binfo_type = TREE_TYPE (jump_func->value.base_binfo);
-         fprintf (f, "KNOWN TYPE, type in binfo is: ");
-         print_generic_expr (f, binfo_type, 0);
-         fprintf (f, " (%u)\n", TYPE_UID (binfo_type));
+         fprintf (f, "KNOWN TYPE: base  ");
+         print_generic_expr (f, jump_func->value.known_type.base_type, 0);
+         fprintf (f, ", offset "HOST_WIDE_INT_PRINT_DEC", component ",
+                  jump_func->value.known_type.offset);
+         print_generic_expr (f, jump_func->value.known_type.component_type, 0);
+         fprintf (f, "\n");
        }
       else if (type == IPA_JF_CONST)
        {
        }
       else if (type == IPA_JF_CONST)
        {
@@ -265,25 +188,22 @@ ipa_print_node_jump_functions_for_edge (FILE *f, struct cgraph_edge *cs)
            }
          fprintf (f, "\n");
        }
            }
          fprintf (f, "\n");
        }
-      else if (type == IPA_JF_CONST_MEMBER_PTR)
-       {
-         fprintf (f, "CONST MEMBER PTR: ");
-         print_generic_expr (f, jump_func->value.member_cst.pfn, 0);
-         fprintf (f, ", ");
-         print_generic_expr (f, jump_func->value.member_cst.delta, 0);
-         fprintf (f, "\n");
-       }
       else if (type == IPA_JF_PASS_THROUGH)
        {
          fprintf (f, "PASS THROUGH: ");
       else if (type == IPA_JF_PASS_THROUGH)
        {
          fprintf (f, "PASS THROUGH: ");
-         fprintf (f, "%d, op %s ",
+         fprintf (f, "%d, op %s",
                   jump_func->value.pass_through.formal_id,
                   tree_code_name[(int)
                                  jump_func->value.pass_through.operation]);
          if (jump_func->value.pass_through.operation != NOP_EXPR)
                   jump_func->value.pass_through.formal_id,
                   tree_code_name[(int)
                                  jump_func->value.pass_through.operation]);
          if (jump_func->value.pass_through.operation != NOP_EXPR)
-           print_generic_expr (dump_file,
-                               jump_func->value.pass_through.operand, 0);
-         fprintf (dump_file, "\n");
+           {
+             fprintf (f, " ");
+             print_generic_expr (f,
+                                 jump_func->value.pass_through.operand, 0);
+           }
+         if (jump_func->value.pass_through.agg_preserved)
+           fprintf (f, ", agg_preserved");
+         fprintf (f, "\n");
        }
       else if (type == IPA_JF_ANCESTOR)
        {
        }
       else if (type == IPA_JF_ANCESTOR)
        {
@@ -292,7 +212,32 @@ ipa_print_node_jump_functions_for_edge (FILE *f, struct cgraph_edge *cs)
                   jump_func->value.ancestor.formal_id,
                   jump_func->value.ancestor.offset);
          print_generic_expr (f, jump_func->value.ancestor.type, 0);
                   jump_func->value.ancestor.formal_id,
                   jump_func->value.ancestor.offset);
          print_generic_expr (f, jump_func->value.ancestor.type, 0);
-         fprintf (dump_file, "\n");
+         if (jump_func->value.ancestor.agg_preserved)
+           fprintf (f, ", agg_preserved");
+         fprintf (f, "\n");
+       }
+
+      if (jump_func->agg.items)
+       {
+         struct ipa_agg_jf_item *item;
+         int j;
+
+         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)
+           {
+             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_low_cst (TYPE_SIZE (item->value), 1));
+             else
+               {
+                 fprintf (f, "cst: ");
+                 print_generic_expr (f, item->value, 0);
+               }
+             fprintf (f, "\n");
+           }
        }
     }
 }
        }
     }
 }
@@ -314,8 +259,8 @@ ipa_print_node_jump_functions (FILE *f, struct cgraph_node *node)
        continue;
 
       fprintf (f, "    callsite  %s/%i -> %s/%i : \n",
        continue;
 
       fprintf (f, "    callsite  %s/%i -> %s/%i : \n",
-              cgraph_node_name (node), node->uid,
-              cgraph_node_name (cs->callee), cs->callee->uid);
+              xstrdup (cgraph_node_name (node)), node->uid,
+              xstrdup (cgraph_node_name (cs->callee)), cs->callee->uid);
       ipa_print_node_jump_functions_for_edge (f, cs);
     }
 
       ipa_print_node_jump_functions_for_edge (f, cs);
     }
 
@@ -344,19 +289,118 @@ ipa_print_all_jump_functions (FILE *f)
   struct cgraph_node *node;
 
   fprintf (f, "\nJump functions:\n");
   struct cgraph_node *node;
 
   fprintf (f, "\nJump functions:\n");
-  for (node = cgraph_nodes; node; node = node->next)
+  FOR_EACH_FUNCTION (node)
     {
       ipa_print_node_jump_functions (f, node);
     }
 }
 
     {
       ipa_print_node_jump_functions (f, node);
     }
 }
 
+/* Worker for prune_expression_for_jf.  */
+
+static tree
+prune_expression_for_jf_1 (tree *tp, int *walk_subtrees, void *)
+{
+  if (EXPR_P (*tp))
+    SET_EXPR_LOCATION (*tp, UNKNOWN_LOCATION);
+  else
+    *walk_subtrees = 0;
+  return NULL_TREE;
+}
+
+/* Return the expression tree EXPR unshared and with location stripped off.  */
+
+static tree
+prune_expression_for_jf (tree exp)
+{
+  if (EXPR_P (exp))
+    {
+      exp = unshare_expr (exp);
+      walk_tree (&exp, prune_expression_for_jf_1, NULL, NULL);
+    }
+  return exp;
+}
+
+/* Set JFUNC to be a known type jump function.  */
+
+static void
+ipa_set_jf_known_type (struct ipa_jump_func *jfunc, HOST_WIDE_INT offset,
+                      tree base_type, tree component_type)
+{
+  jfunc->type = IPA_JF_KNOWN_TYPE;
+  jfunc->value.known_type.offset = offset,
+  jfunc->value.known_type.base_type = base_type;
+  jfunc->value.known_type.component_type = component_type;
+}
+
+/* Set JFUNC to be a constant jmp function.  */
+
+static void
+ipa_set_jf_constant (struct ipa_jump_func *jfunc, tree constant)
+{
+  constant = unshare_expr (constant);
+  if (constant && EXPR_P (constant))
+    SET_EXPR_LOCATION (constant, UNKNOWN_LOCATION);
+  jfunc->type = IPA_JF_CONST;
+  jfunc->value.constant = prune_expression_for_jf (constant);
+}
+
+/* Set JFUNC to be a simple pass-through jump function.  */
+static void
+ipa_set_jf_simple_pass_through (struct ipa_jump_func *jfunc, int formal_id,
+                               bool agg_preserved)
+{
+  jfunc->type = IPA_JF_PASS_THROUGH;
+  jfunc->value.pass_through.operand = NULL_TREE;
+  jfunc->value.pass_through.formal_id = formal_id;
+  jfunc->value.pass_through.operation = NOP_EXPR;
+  jfunc->value.pass_through.agg_preserved = agg_preserved;
+}
+
+/* Set JFUNC to be an arithmetic pass through jump function.  */
+
+static void
+ipa_set_jf_arith_pass_through (struct ipa_jump_func *jfunc, int formal_id,
+                              tree operand, enum tree_code operation)
+{
+  jfunc->type = IPA_JF_PASS_THROUGH;
+  jfunc->value.pass_through.operand = prune_expression_for_jf (operand);
+  jfunc->value.pass_through.formal_id = formal_id;
+  jfunc->value.pass_through.operation = operation;
+  jfunc->value.pass_through.agg_preserved = false;
+}
+
+/* Set JFUNC to be an ancestor jump function.  */
+
+static void
+ipa_set_ancestor_jf (struct ipa_jump_func *jfunc, HOST_WIDE_INT offset,
+                    tree type, int formal_id, bool agg_preserved)
+{
+  jfunc->type = IPA_JF_ANCESTOR;
+  jfunc->value.ancestor.formal_id = formal_id;
+  jfunc->value.ancestor.offset = offset;
+  jfunc->value.ancestor.type = type;
+  jfunc->value.ancestor.agg_preserved = agg_preserved;
+}
+
 /* Structure to be passed in between detect_type_change and
    check_stmt_for_type_change.  */
 
 struct type_change_info
 {
 /* Structure to be passed in between detect_type_change and
    check_stmt_for_type_change.  */
 
 struct type_change_info
 {
+  /* Offset into the object where there is the virtual method pointer we are
+     looking for.  */
+  HOST_WIDE_INT offset;
+  /* The declaration or SSA_NAME pointer of the base that we are checking for
+     type change.  */
+  tree object;
+  /* If we actually can tell the type that the object has changed to, it is
+     stored in this field.  Otherwise it remains NULL_TREE.  */
+  tree known_current_type;
   /* Set to true if dynamic type change has been detected.  */
   bool type_maybe_changed;
   /* Set to true if dynamic type change has been detected.  */
   bool type_maybe_changed;
+  /* Set to true if multiple types have been encountered.  known_current_type
+     must be disregarded in that case.  */
+  bool multiple_types_encountered;
 };
 
 /* Return true if STMT can modify a virtual method table pointer.
 };
 
 /* Return true if STMT can modify a virtual method table pointer.
@@ -422,6 +466,50 @@ stmt_may_be_vtbl_ptr_store (gimple stmt)
   return true;
 }
 
   return true;
 }
 
+/* If STMT can be proved to be an assignment to the virtual method table
+   pointer of ANALYZED_OBJ and the type associated with the new table
+   identified, return the type.  Otherwise return NULL_TREE.  */
+
+static tree
+extr_type_from_vtbl_ptr_store (gimple stmt, struct type_change_info *tci)
+{
+  HOST_WIDE_INT offset, size, max_size;
+  tree lhs, rhs, base;
+
+  if (!gimple_assign_single_p (stmt))
+    return NULL_TREE;
+
+  lhs = gimple_assign_lhs (stmt);
+  rhs = gimple_assign_rhs1 (stmt);
+  if (TREE_CODE (lhs) != COMPONENT_REF
+      || !DECL_VIRTUAL_P (TREE_OPERAND (lhs, 1))
+      || TREE_CODE (rhs) != ADDR_EXPR)
+    return NULL_TREE;
+  rhs = get_base_address (TREE_OPERAND (rhs, 0));
+  if (!rhs
+      || TREE_CODE (rhs) != VAR_DECL
+      || !DECL_VIRTUAL_P (rhs))
+    return NULL_TREE;
+
+  base = get_ref_base_and_extent (lhs, &offset, &size, &max_size);
+  if (offset != tci->offset
+      || size != POINTER_SIZE
+      || max_size != POINTER_SIZE)
+    return NULL_TREE;
+  if (TREE_CODE (base) == MEM_REF)
+    {
+      if (TREE_CODE (tci->object) != MEM_REF
+         || TREE_OPERAND (tci->object, 0) != TREE_OPERAND (base, 0)
+         || !tree_int_cst_equal (TREE_OPERAND (tci->object, 1),
+                                 TREE_OPERAND (base, 1)))
+       return NULL_TREE;
+    }
+  else if (tci->object != base)
+    return NULL_TREE;
+
+  return DECL_CONTEXT (rhs);
+}
+
 /* Callback of walk_aliased_vdefs and a helper function for
    detect_type_change to check whether a particular statement may modify
    the virtual table pointer, and if possible also determine the new type of
 /* Callback of walk_aliased_vdefs and a helper function for
    detect_type_change to check whether a particular statement may modify
    the virtual table pointer, and if possible also determine the new type of
@@ -436,6 +524,12 @@ check_stmt_for_type_change (ao_ref *ao ATTRIBUTE_UNUSED, tree vdef, void *data)
 
   if (stmt_may_be_vtbl_ptr_store (stmt))
     {
 
   if (stmt_may_be_vtbl_ptr_store (stmt))
     {
+      tree type;
+      type = extr_type_from_vtbl_ptr_store (stmt, tci);
+      if (tci->type_maybe_changed
+         && type != tci->known_current_type)
+       tci->multiple_types_encountered = true;
+      tci->known_current_type = type;
       tci->type_maybe_changed = true;
       return true;
     }
       tci->type_maybe_changed = true;
       return true;
     }
@@ -443,16 +537,15 @@ check_stmt_for_type_change (ao_ref *ao ATTRIBUTE_UNUSED, tree vdef, void *data)
     return false;
 }
 
     return false;
 }
 
-/* Detect whether the dynamic type of ARG 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 to it, unless
-   dereferenced).  BASE is the base of the memory access as returned by
-   get_ref_base_and_extent, as is the offset.  */
+
+
+/* Like detect_type_change but with extra argument COMP_TYPE which will become
+   the component type part of new JFUNC of dynamic type change is detected and
+   the new base type is identified.  */
 
 static bool
 
 static bool
-detect_type_change (tree arg, tree base, gimple call,
-                   struct ipa_jump_func *jfunc, HOST_WIDE_INT offset)
+detect_type_change_1 (tree arg, tree base, tree comp_type, gimple call,
+                     struct ipa_jump_func *jfunc, HOST_WIDE_INT offset)
 {
   struct type_change_info tci;
   ao_ref ao;
 {
   struct type_change_info tci;
   ao_ref ao;
@@ -465,25 +558,47 @@ detect_type_change (tree arg, tree base, gimple call,
   if (!flag_devirtualize || !gimple_vuse (call))
     return false;
 
   if (!flag_devirtualize || !gimple_vuse (call))
     return false;
 
-  tci.type_maybe_changed = false;
-
-  ao.ref = arg;
+  ao_ref_init (&ao, arg);
   ao.base = base;
   ao.offset = offset;
   ao.size = POINTER_SIZE;
   ao.max_size = ao.size;
   ao.base = base;
   ao.offset = offset;
   ao.size = POINTER_SIZE;
   ao.max_size = ao.size;
-  ao.ref_alias_set = -1;
-  ao.base_alias_set = -1;
+
+  tci.offset = offset;
+  tci.object = get_base_address (arg);
+  tci.known_current_type = NULL_TREE;
+  tci.type_maybe_changed = false;
+  tci.multiple_types_encountered = false;
 
   walk_aliased_vdefs (&ao, gimple_vuse (call), check_stmt_for_type_change,
                      &tci, NULL);
   if (!tci.type_maybe_changed)
     return false;
 
 
   walk_aliased_vdefs (&ao, gimple_vuse (call), check_stmt_for_type_change,
                      &tci, NULL);
   if (!tci.type_maybe_changed)
     return false;
 
-  jfunc->type = IPA_JF_UNKNOWN;
+  if (!tci.known_current_type
+      || tci.multiple_types_encountered
+      || offset != 0)
+    jfunc->type = IPA_JF_UNKNOWN;
+  else
+    ipa_set_jf_known_type (jfunc, 0, tci.known_current_type, comp_type);
+
   return true;
 }
 
   return true;
 }
 
+/* Detect whether the dynamic type of ARG 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 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, gimple call,
+                   struct ipa_jump_func *jfunc, HOST_WIDE_INT offset)
+{
+  return detect_type_change_1 (arg, base, TREE_TYPE (arg), call, jfunc, offset);
+}
+
 /* Like detect_type_change but ARG is supposed to be a non-dereferenced pointer
    SSA name (its dereference will become the base and the offset is assumed to
    be zero).  */
 /* Like detect_type_change but ARG is supposed to be a non-dereferenced pointer
    SSA name (its dereference will become the base and the offset is assumed to
    be zero).  */
@@ -491,43 +606,320 @@ detect_type_change (tree arg, tree base, gimple call,
 static bool
 detect_type_change_ssa (tree arg, gimple call, struct ipa_jump_func *jfunc)
 {
 static bool
 detect_type_change_ssa (tree arg, gimple call, struct ipa_jump_func *jfunc)
 {
+  tree comp_type;
+
   gcc_checking_assert (TREE_CODE (arg) == SSA_NAME);
   if (!flag_devirtualize
       || !POINTER_TYPE_P (TREE_TYPE (arg))
       || TREE_CODE (TREE_TYPE (TREE_TYPE (arg))) != RECORD_TYPE)
     return false;
 
   gcc_checking_assert (TREE_CODE (arg) == SSA_NAME);
   if (!flag_devirtualize
       || !POINTER_TYPE_P (TREE_TYPE (arg))
       || TREE_CODE (TREE_TYPE (TREE_TYPE (arg))) != RECORD_TYPE)
     return false;
 
+  comp_type = TREE_TYPE (TREE_TYPE (arg));
   arg = build2 (MEM_REF, ptr_type_node, arg,
   arg = build2 (MEM_REF, ptr_type_node, arg,
-                build_int_cst (ptr_type_node, 0));
+               build_int_cst (ptr_type_node, 0));
+
+  return detect_type_change_1 (arg, arg, comp_type, call, jfunc, 0);
+}
+
+/* Callback of walk_aliased_vdefs.  Flags that it has been invoked to the
+   boolean variable pointed to by DATA.  */
+
+static bool
+mark_modified (ao_ref *ao ATTRIBUTE_UNUSED, tree vdef ATTRIBUTE_UNUSED,
+                    void *data)
+{
+  bool *b = (bool *) data;
+  *b = true;
+  return true;
+}
+
+/* Return true if a load from a formal parameter PARM_LOAD is known to retreive
+   a value known not to be modified in this function before reaching the
+   statement STMT.  PARM_AINFO is a pointer to a structure containing temporary
+   information about the parameter.  */
+
+static bool
+parm_preserved_before_stmt_p (struct param_analysis_info *parm_ainfo,
+                              gimple stmt, tree parm_load)
+{
+  bool modified = false;
+  bitmap *visited_stmts;
+  ao_ref refd;
 
 
-  return detect_type_change (arg, arg, call, jfunc, 0);
+  if (parm_ainfo && parm_ainfo->parm_modified)
+    return false;
+
+  gcc_checking_assert (gimple_vuse (stmt) != NULL_TREE);
+  ao_ref_init (&refd, parm_load);
+  /* We can cache visited statements only when parm_ainfo is available and when
+     we are looking at a naked load of the whole parameter.  */
+  if (!parm_ainfo || TREE_CODE (parm_load) != PARM_DECL)
+    visited_stmts = NULL;
+  else
+    visited_stmts = &parm_ainfo->parm_visited_statements;
+  walk_aliased_vdefs (&refd, gimple_vuse (stmt), mark_modified, &modified,
+                     visited_stmts);
+  if (parm_ainfo && modified)
+    parm_ainfo->parm_modified = true;
+  return !modified;
 }
 
 }
 
+/* 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 (vec<ipa_param_descriptor_t> descriptors,
+                           struct param_analysis_info *parms_ainfo,
+                           gimple stmt)
+{
+  int index;
+  tree op1;
+
+  if (!gimple_assign_single_p (stmt))
+    return -1;
+
+  op1 = gimple_assign_rhs1 (stmt);
+  if (TREE_CODE (op1) != PARM_DECL)
+    return -1;
+
+  index = ipa_get_param_decl_index_1 (descriptors, op1);
+  if (index < 0
+      || !parm_preserved_before_stmt_p (parms_ainfo ? &parms_ainfo[index]
+                                       : NULL, stmt, op1))
+    return -1;
+
+  return index;
+}
+
+/* Return true if memory reference REF loads data that are known to be
+   unmodified in this function before reaching statement STMT.  PARM_AINFO, if
+   non-NULL, is a pointer to a structure containing temporary information about
+   PARM.  */
+
+static bool
+parm_ref_data_preserved_p (struct param_analysis_info *parm_ainfo,
+                             gimple stmt, tree ref)
+{
+  bool modified = false;
+  ao_ref refd;
+
+  gcc_checking_assert (gimple_vuse (stmt));
+  if (parm_ainfo && parm_ainfo->ref_modified)
+    return false;
+
+  ao_ref_init (&refd, ref);
+  walk_aliased_vdefs (&refd, gimple_vuse (stmt), mark_modified, &modified,
+                     NULL);
+  if (parm_ainfo && modified)
+    parm_ainfo->ref_modified = true;
+  return !modified;
+}
+
+/* Return true if the data pointed to by PARM is known to be unmodified in this
+   function before reaching call statement CALL into which it is passed.
+   PARM_AINFO is a pointer to a structure containing temporary information
+   about PARM.  */
+
+static bool
+parm_ref_data_pass_through_p (struct param_analysis_info *parm_ainfo,
+                              gimple call, tree parm)
+{
+  bool modified = false;
+  ao_ref refd;
+
+  /* It's unnecessary to calculate anything about memory contnets for a const
+     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)))
+    return false;
+
+  if (parm_ainfo->pt_modified)
+    return false;
+
+  ao_ref_init_from_ptr_and_size (&refd, parm, NULL_TREE);
+  walk_aliased_vdefs (&refd, gimple_vuse (call), mark_modified, &modified,
+                     parm_ainfo ? &parm_ainfo->pt_visited_statements : NULL);
+  if (modified)
+    parm_ainfo->pt_modified = true;
+  return !modified;
+}
+
+/* Return true if we can prove that OP is a memory reference loading unmodified
+   data from an aggregate passed as a parameter and if the aggregate is passed
+   by reference, that the alias type of the load corresponds to the type of the
+   formal parameter (so that we can rely on this type for TBAA in callers).
+   INFO and PARMS_AINFO describe parameters of the current function (but the
+   latter can be NULL), STMT is the load statement.  If function returns true,
+   *INDEX_P, *OFFSET_P and *BY_REF is filled with the parameter index, offset
+   within the aggregate and whether it is a load from a value passed by
+   reference respectively.  */
+
+static bool
+ipa_load_from_parm_agg_1 (vec<ipa_param_descriptor_t> descriptors,
+                         struct param_analysis_info *parms_ainfo, gimple stmt,
+                         tree op, int *index_p, HOST_WIDE_INT *offset_p,
+                         bool *by_ref_p)
+{
+  int index;
+  HOST_WIDE_INT size, max_size;
+  tree base = get_ref_base_and_extent (op, offset_p, &size, &max_size);
+
+  if (max_size == -1 || max_size != size || *offset_p < 0)
+    return false;
+
+  if (DECL_P (base))
+    {
+      int index = ipa_get_param_decl_index_1 (descriptors, base);
+      if (index >= 0
+         && parm_preserved_before_stmt_p (parms_ainfo ? &parms_ainfo[index]
+                                          : NULL, stmt, op))
+       {
+         *index_p = index;
+         *by_ref_p = false;
+         return true;
+       }
+      return false;
+    }
+
+  if (TREE_CODE (base) != MEM_REF
+          || TREE_CODE (TREE_OPERAND (base, 0)) != SSA_NAME
+          || !integer_zerop (TREE_OPERAND (base, 1)))
+    return false;
+
+  if (SSA_NAME_IS_DEFAULT_DEF (TREE_OPERAND (base, 0)))
+    {
+      tree parm = SSA_NAME_VAR (TREE_OPERAND (base, 0));
+      index = ipa_get_param_decl_index_1 (descriptors, parm);
+    }
+  else
+    {
+      /* This branch catches situations where a pointer parameter is not a
+        gimple register, for example:
+
+        void hip7(S*) (struct S * p)
+        {
+        void (*<T2e4>) (struct S *) D.1867;
+        struct S * p.1;
+
+        <bb 2>:
+        p.1_1 = p;
+        D.1867_2 = p.1_1->f;
+        D.1867_2 ();
+        gdp = &p;
+      */
+
+      gimple def = SSA_NAME_DEF_STMT (TREE_OPERAND (base, 0));
+      index = load_from_unmodified_param (descriptors, parms_ainfo, def);
+    }
+
+  if (index >= 0
+      && parm_ref_data_preserved_p (parms_ainfo ? &parms_ainfo[index] : NULL,
+                                   stmt, op))
+    {
+      *index_p = index;
+      *by_ref_p = true;
+      return true;
+    }
+  return false;
+}
+
+/* Just like the previous function, just without the param_analysis_info
+   pointer, for users outside of this file.  */
+
+bool
+ipa_load_from_parm_agg (struct ipa_node_params *info, gimple stmt,
+                       tree op, int *index_p, HOST_WIDE_INT *offset_p,
+                       bool *by_ref_p)
+{
+  return ipa_load_from_parm_agg_1 (info->descriptors, NULL, stmt, op, index_p,
+                                  offset_p, by_ref_p);
+}
 
 /* Given that an actual argument is an SSA_NAME (given in NAME) and is a result
 
 /* Given that an actual argument is an SSA_NAME (given in NAME) and is a result
-   of an assignment statement STMT, try to find out whether NAME can be
-   described by a (possibly polynomial) pass-through jump-function or an
-   ancestor jump function and if so, write the appropriate function into
-   JFUNC */
+   of an assignment statement STMT, try to determine whether we are actually
+   handling any of the following cases and construct an appropriate jump
+   function into JFUNC if so:
+
+   1) The passed value is loaded from a formal parameter which is not a gimple
+   register (most probably because it is addressable, the value has to be
+   scalar) and we can guarantee the value has not changed.  This case can
+   therefore be described by a simple pass-through jump function.  For example:
+
+      foo (int a)
+      {
+        int a.0;
+
+        a.0_2 = a;
+        bar (a.0_2);
+
+   2) The passed value can be described by a simple arithmetic pass-through
+   jump function. E.g.
+
+      foo (int a)
+      {
+        int D.2064;
+
+        D.2064_4 = a.1(D) + 4;
+        bar (D.2064_4);
+
+   This case can also occur in combination of the previous one, e.g.:
+
+      foo (int a, int z)
+      {
+        int a.0;
+        int D.2064;
+
+       a.0_3 = a;
+       D.2064_4 = a.0_3 + 4;
+       foo (D.2064_4);
+
+   3) The passed value is an address of an object within another one (which
+   also passed by reference).  Such situations are described by an ancestor
+   jump function and describe situations such as:
+
+     B::foo() (struct B * const this)
+     {
+       struct A * D.1845;
+
+       D.1845_2 = &this_1(D)->D.1748;
+       A::bar (D.1845_2);
+
+   INFO is the structure describing individual parameters access different
+   stages of IPA optimizations.  PARMS_AINFO contains the information that is
+   only needed for intraprocedural analysis.  */
 
 static void
 compute_complex_assign_jump_func (struct ipa_node_params *info,
 
 static void
 compute_complex_assign_jump_func (struct ipa_node_params *info,
+                                 struct param_analysis_info *parms_ainfo,
                                  struct ipa_jump_func *jfunc,
                                  gimple call, gimple stmt, tree name)
 {
   HOST_WIDE_INT offset, size, max_size;
                                  struct ipa_jump_func *jfunc,
                                  gimple call, gimple stmt, tree name)
 {
   HOST_WIDE_INT offset, size, max_size;
-  tree op1, op2, base, ssa;
+  tree op1, tc_ssa, base, ssa;
   int index;
 
   op1 = gimple_assign_rhs1 (stmt);
   int index;
 
   op1 = gimple_assign_rhs1 (stmt);
-  op2 = gimple_assign_rhs2 (stmt);
 
 
-  if (TREE_CODE (op1) == SSA_NAME
-      && SSA_NAME_IS_DEFAULT_DEF (op1))
+  if (TREE_CODE (op1) == SSA_NAME)
     {
     {
-      index = ipa_get_param_decl_index (info, SSA_NAME_VAR (op1));
-      if (index < 0)
-       return;
+      if (SSA_NAME_IS_DEFAULT_DEF (op1))
+       index = ipa_get_param_decl_index (info, SSA_NAME_VAR (op1));
+      else
+       index = load_from_unmodified_param (info->descriptors, parms_ainfo,
+                                           SSA_NAME_DEF_STMT (op1));
+      tc_ssa = op1;
+    }
+  else
+    {
+      index = load_from_unmodified_param (info->descriptors, parms_ainfo, stmt);
+      tc_ssa = gimple_assign_lhs (stmt);
+    }
+
+  if (index >= 0)
+    {
+      tree op2 = gimple_assign_rhs2 (stmt);
 
       if (op2)
        {
 
       if (op2)
        {
@@ -537,17 +929,15 @@ compute_complex_assign_jump_func (struct ipa_node_params *info,
                                                 TREE_TYPE (op1))))
            return;
 
                                                 TREE_TYPE (op1))))
            return;
 
-         jfunc->type = IPA_JF_PASS_THROUGH;
-         jfunc->value.pass_through.formal_id = index;
-         jfunc->value.pass_through.operation = gimple_assign_rhs_code (stmt);
-         jfunc->value.pass_through.operand = op2;
+         ipa_set_jf_arith_pass_through (jfunc, index, op2,
+                                        gimple_assign_rhs_code (stmt));
        }
        }
-      else if (gimple_assign_unary_nop_p (stmt)
-              && !detect_type_change_ssa (op1, call, jfunc))
+      else if (gimple_assign_single_p (stmt)
+              && !detect_type_change_ssa (tc_ssa, call, jfunc))
        {
        {
-         jfunc->type = IPA_JF_PASS_THROUGH;
-         jfunc->value.pass_through.formal_id = index;
-         jfunc->value.pass_through.operation = NOP_EXPR;
+         bool agg_p = parm_ref_data_pass_through_p (&parms_ainfo[index],
+                                                    call, tc_ssa);
+         ipa_set_jf_simple_pass_through (jfunc, index, agg_p);
        }
       return;
     }
        }
       return;
     }
@@ -574,12 +964,9 @@ compute_complex_assign_jump_func (struct ipa_node_params *info,
   index = ipa_get_param_decl_index (info, SSA_NAME_VAR (ssa));
   if (index >= 0
       && !detect_type_change (op1, base, call, jfunc, offset))
   index = ipa_get_param_decl_index (info, SSA_NAME_VAR (ssa));
   if (index >= 0
       && !detect_type_change (op1, base, call, jfunc, offset))
-    {
-      jfunc->type = IPA_JF_ANCESTOR;
-      jfunc->value.ancestor.formal_id = index;
-      jfunc->value.ancestor.offset = offset;
-      jfunc->value.ancestor.type = TREE_TYPE (op1);
-    }
+    ipa_set_ancestor_jf (jfunc, offset, TREE_TYPE (op1), index,
+                        parm_ref_data_pass_through_p (&parms_ainfo[index],
+                                                      call, ssa));
 }
 
 /* Extract the base, offset and MEM_REF expression from a statement ASSIGN if
 }
 
 /* Extract the base, offset and MEM_REF expression from a statement ASSIGN if
@@ -650,6 +1037,7 @@ get_ancestor_addr_info (gimple assign, tree *obj_p, HOST_WIDE_INT *offset)
 
 static void
 compute_complex_ancestor_jump_func (struct ipa_node_params *info,
 
 static void
 compute_complex_ancestor_jump_func (struct ipa_node_params *info,
+                                   struct param_analysis_info *parms_ainfo,
                                    struct ipa_jump_func *jfunc,
                                    gimple call, gimple phi)
 {
                                    struct ipa_jump_func *jfunc,
                                    gimple call, gimple phi)
 {
@@ -703,12 +1091,9 @@ compute_complex_ancestor_jump_func (struct ipa_node_params *info,
     }
 
   if (!detect_type_change (obj, expr, call, jfunc, offset))
     }
 
   if (!detect_type_change (obj, expr, call, jfunc, offset))
-    {
-      jfunc->type = IPA_JF_ANCESTOR;
-      jfunc->value.ancestor.formal_id = index;
-      jfunc->value.ancestor.offset = offset;
-      jfunc->value.ancestor.type = TREE_TYPE (obj);
-    }
+    ipa_set_ancestor_jf (jfunc, offset, TREE_TYPE (obj), index,
+                        parm_ref_data_pass_through_p (&parms_ainfo[index],
+                                                      call, parm));
 }
 
 /* Given OP which is passed as an actual argument to a called function,
 }
 
 /* Given OP which is passed as an actual argument to a called function,
@@ -720,7 +1105,7 @@ compute_known_type_jump_func (tree op, struct ipa_jump_func *jfunc,
                              gimple call)
 {
   HOST_WIDE_INT offset, size, max_size;
                              gimple call)
 {
   HOST_WIDE_INT offset, size, max_size;
-  tree base, binfo;
+  tree base;
 
   if (!flag_devirtualize
       || TREE_CODE (op) != ADDR_EXPR
 
   if (!flag_devirtualize
       || TREE_CODE (op) != ADDR_EXPR
@@ -733,75 +1118,14 @@ compute_known_type_jump_func (tree op, struct ipa_jump_func *jfunc,
       || max_size == -1
       || max_size != size
       || TREE_CODE (TREE_TYPE (base)) != RECORD_TYPE
       || max_size == -1
       || max_size != size
       || TREE_CODE (TREE_TYPE (base)) != RECORD_TYPE
-      || is_global_var (base))
-    return;
-
-  if (detect_type_change (op, base, call, jfunc, offset))
-    return;
-
-  binfo = TYPE_BINFO (TREE_TYPE (base));
-  if (!binfo)
-    return;
-  binfo = get_binfo_at_offset (binfo, offset, TREE_TYPE (op));
-  if (binfo)
-    {
-      jfunc->type = IPA_JF_KNOWN_TYPE;
-      jfunc->value.base_binfo = binfo;
-    }
-}
-
-
-/* Determine the jump functions of scalar arguments.  Scalar means SSA names
-   and constants of a number of selected types.  INFO is the ipa_node_params
-   structure associated with the caller, FUNCTIONS is a pointer to an array of
-   jump function structures associated with CALL which is the call statement
-   being examined.*/
-
-static void
-compute_scalar_jump_functions (struct ipa_node_params *info,
-                              struct ipa_jump_func *functions,
-                              gimple call)
-{
-  tree arg;
-  unsigned num = 0;
-
-  for (num = 0; num < gimple_call_num_args (call); num++)
-    {
-      arg = gimple_call_arg (call, num);
+      || is_global_var (base))
+    return;
 
 
-      if (is_gimple_ip_invariant (arg))
-       {
-         functions[num].type = IPA_JF_CONST;
-         functions[num].value.constant = arg;
-       }
-      else if (TREE_CODE (arg) == SSA_NAME)
-       {
-         if (SSA_NAME_IS_DEFAULT_DEF (arg))
-           {
-             int index = ipa_get_param_decl_index (info, SSA_NAME_VAR (arg));
+  if (!TYPE_BINFO (TREE_TYPE (base))
+      || detect_type_change (op, base, call, jfunc, offset))
+    return;
 
 
-             if (index >= 0
-                 && !detect_type_change_ssa (arg, call, &functions[num]))
-               {
-                 functions[num].type = IPA_JF_PASS_THROUGH;
-                 functions[num].value.pass_through.formal_id = index;
-                 functions[num].value.pass_through.operation = NOP_EXPR;
-               }
-           }
-         else
-           {
-             gimple stmt = SSA_NAME_DEF_STMT (arg);
-             if (is_gimple_assign (stmt))
-               compute_complex_assign_jump_func (info, &functions[num],
-                                                 call, stmt, arg);
-             else if (gimple_code (stmt) == GIMPLE_PHI)
-               compute_complex_ancestor_jump_func (info, &functions[num],
-                                                   call, stmt);
-           }
-       }
-      else
-       compute_known_type_jump_func (arg, &functions[num], call);
-    }
+  ipa_set_jf_known_type (jfunc, offset, TREE_TYPE (base), TREE_TYPE (op));
 }
 
 /* Inspect the given TYPE and return true iff it has the same structure (the
 }
 
 /* Inspect the given TYPE and return true iff it has the same structure (the
@@ -819,14 +1143,16 @@ type_like_member_ptr_p (tree type, tree *method_ptr, tree *delta)
 
   fld = TYPE_FIELDS (type);
   if (!fld || !POINTER_TYPE_P (TREE_TYPE (fld))
 
   fld = TYPE_FIELDS (type);
   if (!fld || !POINTER_TYPE_P (TREE_TYPE (fld))
-      || TREE_CODE (TREE_TYPE (TREE_TYPE (fld))) != METHOD_TYPE)
+      || TREE_CODE (TREE_TYPE (TREE_TYPE (fld))) != METHOD_TYPE
+      || !host_integerp (DECL_FIELD_OFFSET (fld), 1))
     return false;
 
   if (method_ptr)
     *method_ptr = fld;
 
   fld = DECL_CHAIN (fld);
     return false;
 
   if (method_ptr)
     *method_ptr = fld;
 
   fld = DECL_CHAIN (fld);
-  if (!fld || INTEGRAL_TYPE_P (fld))
+  if (!fld || INTEGRAL_TYPE_P (fld)
+      || !host_integerp (DECL_FIELD_OFFSET (fld), 1))
     return false;
   if (delta)
     *delta = fld;
     return false;
   if (delta)
     *delta = fld;
@@ -837,102 +1163,9 @@ type_like_member_ptr_p (tree type, tree *method_ptr, tree *delta)
   return true;
 }
 
   return true;
 }
 
-/* Callback of walk_aliased_vdefs.  Flags that it has been invoked to the
-   boolean variable pointed to by DATA.  */
-
-static bool
-mark_modified (ao_ref *ao ATTRIBUTE_UNUSED, tree vdef ATTRIBUTE_UNUSED,
-                    void *data)
-{
-  bool *b = (bool *) data;
-  *b = true;
-  return true;
-}
-
-/* Return true if the formal parameter PARM might have been modified in this
-   function before reaching the statement CALL.  PARM_INFO is a pointer to a
-   structure containing intermediate information about PARM.  */
-
-static bool
-is_parm_modified_before_call (struct param_analysis_info *parm_info,
-                             gimple call, tree parm)
-{
-  bool modified = false;
-  ao_ref refd;
-
-  if (parm_info->modified)
-    return true;
-
-  ao_ref_init (&refd, parm);
-  walk_aliased_vdefs (&refd, gimple_vuse (call), mark_modified,
-                     &modified, &parm_info->visited_statements);
-  if (modified)
-    {
-      parm_info->modified = true;
-      return true;
-    }
-  return false;
-}
-
-/* Go through arguments of the CALL and for every one that looks like a member
-   pointer, check whether it can be safely declared pass-through and if so,
-   mark that to the corresponding item of jump FUNCTIONS.  Return true iff
-   there are non-pass-through member pointers within the arguments.  INFO
-   describes formal parameters of the caller.  PARMS_INFO is a pointer to a
-   vector containing intermediate information about each formal parameter.  */
-
-static bool
-compute_pass_through_member_ptrs (struct ipa_node_params *info,
-                                 struct param_analysis_info *parms_info,
-                                 struct ipa_jump_func *functions,
-                                 gimple call)
-{
-  bool undecided_members = false;
-  unsigned num;
-  tree arg;
-
-  for (num = 0; num < gimple_call_num_args (call); num++)
-    {
-      arg = gimple_call_arg (call, num);
-
-      if (type_like_member_ptr_p (TREE_TYPE (arg), NULL, NULL))
-       {
-         if (TREE_CODE (arg) == PARM_DECL)
-           {
-             int index = ipa_get_param_decl_index (info, arg);
-
-             gcc_assert (index >=0);
-             if (!is_parm_modified_before_call (&parms_info[index], call, arg))
-               {
-                 functions[num].type = IPA_JF_PASS_THROUGH;
-                 functions[num].value.pass_through.formal_id = index;
-                 functions[num].value.pass_through.operation = NOP_EXPR;
-               }
-             else
-               undecided_members = true;
-           }
-         else
-           undecided_members = true;
-       }
-    }
-
-  return undecided_members;
-}
-
-/* Simple function filling in a member pointer constant jump function (with PFN
-   and DELTA as the constant value) into JFUNC.  */
-
-static void
-fill_member_ptr_cst_jump_function (struct ipa_jump_func *jfunc,
-                                  tree pfn, tree delta)
-{
-  jfunc->type = IPA_JF_CONST_MEMBER_PTR;
-  jfunc->value.member_cst.pfn = pfn;
-  jfunc->value.member_cst.delta = delta;
-}
-
 /* If RHS is an SSA_NAME and it is defined by a simple copy assign statement,
 /* If RHS is an SSA_NAME and it is defined by a simple copy assign statement,
-   return the rhs of its defining statement.  */
+   return the rhs of its defining statement.  Otherwise return RHS as it
+   is.  */
 
 static inline tree
 get_ssa_def_if_simple_copy (tree rhs)
 
 static inline tree
 get_ssa_def_if_simple_copy (tree rhs)
@@ -949,104 +1182,214 @@ get_ssa_def_if_simple_copy (tree rhs)
   return rhs;
 }
 
   return rhs;
 }
 
-/* Traverse statements from CALL backwards, scanning whether the argument ARG
-   which is a member pointer is filled in with constant values.  If it is, fill
-   the jump function JFUNC in appropriately.  METHOD_FIELD and DELTA_FIELD are
-   fields of the record type of the member pointer.  To give an example, we
-   look for a pattern looking like the following:
+/* Simple linked list, describing known contents of an aggregate beforere
+   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;
+  /* Pointer to the next structure in the list.  */
+  struct ipa_known_agg_contents_list *next;
+};
 
 
-     D.2515.__pfn ={v} printStuff;
-     D.2515.__delta ={v} 0;
-     i_1 = doprinting (D.2515);  */
+/* 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.  JFUNC is the jump function into
+   which the constants are subsequently stored.  */
 
 static void
 
 static void
-determine_cst_member_ptr (gimple call, tree arg, tree method_field,
-                         tree delta_field, struct ipa_jump_func *jfunc)
+determine_known_aggregate_parts (gimple call, tree arg,
+                                struct ipa_jump_func *jfunc)
 {
 {
+  struct ipa_known_agg_contents_list *list = NULL;
+  int item_count = 0, const_count = 0;
+  HOST_WIDE_INT arg_offset, arg_size;
   gimple_stmt_iterator gsi;
   gimple_stmt_iterator gsi;
-  tree method = NULL_TREE;
-  tree delta = NULL_TREE;
+  tree arg_base;
+  bool check_ref, by_ref;
+  ao_ref r;
 
 
-  gsi = gsi_for_stmt (call);
+  /* The function operates in three stages.  First, we prepare check_ref, r,
+     arg_base and arg_offset based on what is actually passed as an actual
+     argument.  */
+
+  if (POINTER_TYPE_P (TREE_TYPE (arg)))
+    {
+      by_ref = true;
+      if (TREE_CODE (arg) == SSA_NAME)
+       {
+         tree type_size;
+          if (!host_integerp (TYPE_SIZE (TREE_TYPE (TREE_TYPE (arg))), 1))
+            return;
+         check_ref = true;
+         arg_base = arg;
+         arg_offset = 0;
+         type_size = TYPE_SIZE (TREE_TYPE (TREE_TYPE (arg)));
+         arg_size = tree_low_cst (type_size, 1);
+         ao_ref_init_from_ptr_and_size (&r, arg_base, NULL_TREE);
+       }
+      else if (TREE_CODE (arg) == ADDR_EXPR)
+       {
+         HOST_WIDE_INT arg_max_size;
+
+         arg = TREE_OPERAND (arg, 0);
+         arg_base = get_ref_base_and_extent (arg, &arg_offset, &arg_size,
+                                         &arg_max_size);
+         if (arg_max_size == -1
+             || arg_max_size != arg_size
+             || arg_offset < 0)
+           return;
+         if (DECL_P (arg_base))
+           {
+             tree size;
+             check_ref = false;
+             size = build_int_cst (integer_type_node, arg_size);
+             ao_ref_init_from_ptr_and_size (&r, arg_base, size);
+           }
+         else
+           return;
+       }
+      else
+       return;
+    }
+  else
+    {
+      HOST_WIDE_INT arg_max_size;
+
+      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);
+      if (arg_max_size == -1
+         || arg_max_size != arg_size
+         || arg_offset < 0)
+       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))
     {
   gsi_prev (&gsi);
   for (; !gsi_end_p (gsi); gsi_prev (&gsi))
     {
+      struct ipa_known_agg_contents_list *n, **p;
       gimple stmt = gsi_stmt (gsi);
       gimple stmt = gsi_stmt (gsi);
-      tree lhs, rhs, fld;
+      HOST_WIDE_INT lhs_offset, lhs_size, lhs_max_size;
+      tree lhs, rhs, lhs_base;
+      bool partial_overlap;
 
 
-      if (!stmt_may_clobber_ref_p (stmt, arg))
+      if (!stmt_may_clobber_ref_p_1 (stmt, &r))
        continue;
       if (!gimple_assign_single_p (stmt))
        continue;
       if (!gimple_assign_single_p (stmt))
-       return;
+       break;
 
       lhs = gimple_assign_lhs (stmt);
       rhs = gimple_assign_rhs1 (stmt);
 
       lhs = gimple_assign_lhs (stmt);
       rhs = gimple_assign_rhs1 (stmt);
+      if (!is_gimple_reg_type (rhs))
+       break;
 
 
-      if (TREE_CODE (lhs) != COMPONENT_REF
-         || TREE_OPERAND (lhs, 0) != arg)
-       return;
+      lhs_base = get_ref_base_and_extent (lhs, &lhs_offset, &lhs_size,
+                                         &lhs_max_size);
+      if (lhs_max_size == -1
+         || lhs_max_size != lhs_size
+         || (lhs_offset < arg_offset
+             && lhs_offset + lhs_size > arg_offset)
+         || (lhs_offset < arg_offset + arg_size
+             && lhs_offset + lhs_size > arg_offset + arg_size))
+       break;
 
 
-      fld = TREE_OPERAND (lhs, 1);
-      if (!method && fld == method_field)
+      if (check_ref)
        {
        {
-         rhs = get_ssa_def_if_simple_copy (rhs);
-         if (TREE_CODE (rhs) == ADDR_EXPR
-             && TREE_CODE (TREE_OPERAND (rhs, 0)) == FUNCTION_DECL
-             && TREE_CODE (TREE_TYPE (TREE_OPERAND (rhs, 0))) == METHOD_TYPE)
-           {
-             method = TREE_OPERAND (rhs, 0);
-             if (delta)
-               {
-                 fill_member_ptr_cst_jump_function (jfunc, rhs, delta);
-                 return;
-               }
-           }
+         if (TREE_CODE (lhs_base) != MEM_REF
+             || TREE_OPERAND (lhs_base, 0) != arg_base
+             || !integer_zerop (TREE_OPERAND (lhs_base, 1)))
+           break;
+       }
+      else if (lhs_base != arg_base)
+       {
+         if (DECL_P (lhs_base))
+           continue;
          else
          else
-           return;
+           break;
        }
 
        }
 
-      if (!delta && fld == delta_field)
+      if (lhs_offset + lhs_size < arg_offset
+         || lhs_offset >= (arg_offset + arg_size))
+       continue;
+
+      partial_overlap = false;
+      p = &list;
+      while (*p && (*p)->offset < lhs_offset)
        {
        {
-         rhs = get_ssa_def_if_simple_copy (rhs);
-         if (TREE_CODE (rhs) == INTEGER_CST)
+         if ((*p)->offset + (*p)->size > lhs_offset)
            {
            {
-             delta = rhs;
-             if (method)
-               {
-                 fill_member_ptr_cst_jump_function (jfunc, rhs, delta);
-                 return;
-               }
+             partial_overlap = true;
+             break;
            }
            }
+         p = &(*p)->next;
+       }
+      if (partial_overlap)
+       break;
+      if (*p && (*p)->offset < lhs_offset + lhs_size)
+       {
+         if ((*p)->offset == lhs_offset && (*p)->size == lhs_size)
+           /* We already know this value is subsequently overwritten with
+              something else.  */
+           continue;
          else
          else
-           return;
+           /* Otherwise this is a partial overlap which we cannot
+              represent.  */
+           break;
        }
        }
-    }
 
 
-  return;
-}
+      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++;
+       }
+      else
+       n->constant = NULL_TREE;
+      n->next = *p;
+      *p = n;
 
 
-/* Go through the arguments of the CALL and for every member pointer within
-   tries determine whether it is a constant.  If it is, create a corresponding
-   constant jump function in FUNCTIONS which is an array of jump functions
-   associated with the call.  */
+      item_count++;
+      if (const_count == PARAM_VALUE (PARAM_IPA_MAX_AGG_ITEMS)
+         || item_count == 2 * PARAM_VALUE (PARAM_IPA_MAX_AGG_ITEMS))
+       break;
+    }
 
 
-static void
-compute_cst_member_ptr_arguments (struct ipa_jump_func *functions,
-                                 gimple call)
-{
-  unsigned num;
-  tree arg, method_field, delta_field;
+  /* 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.  */
 
 
-  for (num = 0; num < gimple_call_num_args (call); num++)
+  if (const_count)
     {
     {
-      arg = gimple_call_arg (call, num);
-
-      if (functions[num].type == IPA_JF_UNKNOWN
-         && type_like_member_ptr_p (TREE_TYPE (arg), &method_field,
-                                    &delta_field))
-       determine_cst_member_ptr (call, arg, method_field, delta_field,
-                                 &functions[num]);
+      jfunc->agg.by_ref = by_ref;
+      vec_alloc (jfunc->agg.items, const_count);
+      while (list)
+       {
+         if (list->constant)
+           {
+             struct ipa_agg_jf_item item;
+             item.offset = list->offset - arg_offset;
+             item.value = prune_expression_for_jf (list->constant);
+             jfunc->agg.items->quick_push (item);
+           }
+         list = list->next;
+       }
     }
 }
 
     }
 }
 
@@ -1055,33 +1398,76 @@ compute_cst_member_ptr_arguments (struct ipa_jump_func *functions,
    to this callsite.  */
 
 static void
    to this callsite.  */
 
 static void
-ipa_compute_jump_functions_for_edge (struct param_analysis_info *parms_info,
+ipa_compute_jump_functions_for_edge (struct param_analysis_info *parms_ainfo,
                                     struct cgraph_edge *cs)
 {
   struct ipa_node_params *info = IPA_NODE_REF (cs->caller);
                                     struct cgraph_edge *cs)
 {
   struct ipa_node_params *info = IPA_NODE_REF (cs->caller);
-  struct ipa_edge_args *arguments = IPA_EDGE_REF (cs);
-  gimple call;
+  struct ipa_edge_args *args = IPA_EDGE_REF (cs);
+  gimple call = cs->call_stmt;
+  int n, arg_num = gimple_call_num_args (call);
 
 
-  if (ipa_get_cs_argument_count (arguments) == 0 || arguments->jump_functions)
+  if (arg_num == 0 || args->jump_functions)
     return;
     return;
-  arguments->jump_functions = ggc_alloc_cleared_vec_ipa_jump_func
-    (ipa_get_cs_argument_count (arguments));
+  vec_safe_grow_cleared (args->jump_functions, arg_num);
 
 
-  call = cs->call_stmt;
-  gcc_assert (is_gimple_call (call));
+  for (n = 0; n < arg_num; n++)
+    {
+      struct ipa_jump_func *jfunc = ipa_get_ith_jump_func (args, n);
+      tree arg = gimple_call_arg (call, n);
 
 
-  /* We will deal with constants and SSA scalars first:  */
-  compute_scalar_jump_functions (info, arguments->jump_functions, call);
+      if (is_gimple_ip_invariant (arg))
+       ipa_set_jf_constant (jfunc, arg);
+      else if (!is_gimple_reg_type (TREE_TYPE (arg))
+              && TREE_CODE (arg) == PARM_DECL)
+       {
+         int index = ipa_get_param_decl_index (info, arg);
 
 
-  /* Let's check whether there are any potential member pointers and if so,
-     whether we can determine their functions as pass_through.  */
-  if (!compute_pass_through_member_ptrs (info, parms_info,
-                                        arguments->jump_functions, call))
-    return;
+         gcc_assert (index >=0);
+         /* Aggregate passed by value, check for pass-through, otherwise we
+            will attempt to fill in aggregate contents later in this
+            for cycle.  */
+         if (parm_preserved_before_stmt_p (&parms_ainfo[index], call, arg))
+           {
+             ipa_set_jf_simple_pass_through (jfunc, index, false);
+             continue;
+           }
+       }
+      else if (TREE_CODE (arg) == SSA_NAME)
+       {
+         if (SSA_NAME_IS_DEFAULT_DEF (arg))
+           {
+             int index = ipa_get_param_decl_index (info, SSA_NAME_VAR (arg));
+             if (index >= 0
+                 && !detect_type_change_ssa (arg, call, jfunc))
+               {
+                 bool agg_p;
+                 agg_p = parm_ref_data_pass_through_p (&parms_ainfo[index],
+                                                       call, arg);
+                 ipa_set_jf_simple_pass_through (jfunc, index, agg_p);
+               }
+           }
+         else
+           {
+             gimple stmt = SSA_NAME_DEF_STMT (arg);
+             if (is_gimple_assign (stmt))
+               compute_complex_assign_jump_func (info, parms_ainfo, jfunc,
+                                                 call, stmt, arg);
+             else if (gimple_code (stmt) == GIMPLE_PHI)
+               compute_complex_ancestor_jump_func (info, parms_ainfo, jfunc,
+                                                   call, stmt);
+           }
+       }
+      else
+       compute_known_type_jump_func (arg, jfunc, call);
 
 
-  /* Finally, let's check whether we actually pass a new constant member
-     pointer here...  */
-  compute_cst_member_ptr_arguments (arguments->jump_functions, call);
+      if ((jfunc->type != IPA_JF_PASS_THROUGH
+             || !ipa_get_jf_pass_through_agg_preserved (jfunc))
+         && (jfunc->type != IPA_JF_ANCESTOR
+             || !ipa_get_jf_ancestor_agg_preserved (jfunc))
+         && (AGGREGATE_TYPE_P (TREE_TYPE (arg))
+             || (POINTER_TYPE_P (TREE_TYPE (arg)))))
+       determine_known_aggregate_parts (call, arg, jfunc);
+    }
 }
 
 /* Compute jump functions for all edges - both direct and indirect - outgoing
 }
 
 /* Compute jump functions for all edges - both direct and indirect - outgoing
@@ -1089,44 +1475,41 @@ ipa_compute_jump_functions_for_edge (struct param_analysis_info *parms_info,
 
 static void
 ipa_compute_jump_functions (struct cgraph_node *node,
 
 static void
 ipa_compute_jump_functions (struct cgraph_node *node,
-                           struct param_analysis_info *parms_info)
+                           struct param_analysis_info *parms_ainfo)
 {
   struct cgraph_edge *cs;
 
   for (cs = node->callees; cs; cs = cs->next_callee)
     {
 {
   struct cgraph_edge *cs;
 
   for (cs = node->callees; cs; cs = cs->next_callee)
     {
+      struct cgraph_node *callee = cgraph_function_or_thunk_node (cs->callee,
+                                                                 NULL);
       /* We do not need to bother analyzing calls to unknown
         functions unless they may become known during lto/whopr.  */
       /* We do not need to bother analyzing calls to unknown
         functions unless they may become known during lto/whopr.  */
-      if (!cs->callee->analyzed && !flag_lto)
+      if (!callee->analyzed && !flag_lto)
        continue;
        continue;
-      ipa_count_arguments (cs);
-      /* If the descriptor of the callee is not initialized yet, we have to do
-        it now. */
-      if (cs->callee->analyzed)
-       ipa_initialize_node_params (cs->callee);
-      if (ipa_get_cs_argument_count (IPA_EDGE_REF (cs))
-         != ipa_get_param_count (IPA_NODE_REF (cs->callee)))
-       ipa_set_called_with_variable_arg (IPA_NODE_REF (cs->callee));
-      ipa_compute_jump_functions_for_edge (parms_info, cs);
+      ipa_compute_jump_functions_for_edge (parms_ainfo, cs);
     }
 
   for (cs = node->indirect_calls; cs; cs = cs->next_callee)
     }
 
   for (cs = node->indirect_calls; cs; cs = cs->next_callee)
-    {
-      ipa_count_arguments (cs);
-      ipa_compute_jump_functions_for_edge (parms_info, cs);
-    }
+    ipa_compute_jump_functions_for_edge (parms_ainfo, cs);
 }
 
 }
 
-/* If RHS looks like a rhs of a statement loading pfn from a member
-   pointer formal parameter, return the parameter, otherwise return
-   NULL.  If USE_DELTA, then we look for a use of the delta field
-   rather than the pfn.  */
+/* If STMT looks like a statement loading a value from a member pointer formal
+   parameter, return that parameter and store the offset of the field to
+   *OFFSET_P, if it is non-NULL.  Otherwise return NULL (but *OFFSET_P still
+   might be clobbered).  If USE_DELTA, then we look for a use of the delta
+   field rather than the pfn.  */
 
 static tree
 
 static tree
-ipa_get_member_ptr_load_param (tree rhs, bool use_delta)
+ipa_get_stmt_member_ptr_load_param (gimple stmt, bool use_delta,
+                                   HOST_WIDE_INT *offset_p)
 {
 {
-  tree rec, ref_field, ref_offset, fld, fld_offset, ptr_field, delta_field;
+  tree rhs, rec, ref_field, ref_offset, fld, ptr_field, delta_field;
+
+  if (!gimple_assign_single_p (stmt))
+    return NULL_TREE;
 
 
+  rhs = gimple_assign_rhs1 (stmt);
   if (TREE_CODE (rhs) == COMPONENT_REF)
     {
       ref_field = TREE_OPERAND (rhs, 1);
   if (TREE_CODE (rhs) == COMPONENT_REF)
     {
       ref_field = TREE_OPERAND (rhs, 1);
@@ -1143,43 +1526,24 @@ ipa_get_member_ptr_load_param (tree rhs, bool use_delta)
   if (TREE_CODE (rec) != PARM_DECL
       || !type_like_member_ptr_p (TREE_TYPE (rec), &ptr_field, &delta_field))
     return NULL_TREE;
   if (TREE_CODE (rec) != PARM_DECL
       || !type_like_member_ptr_p (TREE_TYPE (rec), &ptr_field, &delta_field))
     return NULL_TREE;
-
   ref_offset = TREE_OPERAND (rhs, 1);
 
   ref_offset = TREE_OPERAND (rhs, 1);
 
+  if (use_delta)
+    fld = delta_field;
+  else
+    fld = ptr_field;
+  if (offset_p)
+    *offset_p = int_bit_position (fld);
+
   if (ref_field)
     {
       if (integer_nonzerop (ref_offset))
        return NULL_TREE;
   if (ref_field)
     {
       if (integer_nonzerop (ref_offset))
        return NULL_TREE;
-
-      if (use_delta)
-       fld = delta_field;
-      else
-       fld = ptr_field;
-
       return ref_field == fld ? rec : NULL_TREE;
     }
       return ref_field == fld ? rec : NULL_TREE;
     }
-
-  if (use_delta)
-    fld_offset = byte_position (delta_field);
   else
   else
-    fld_offset = byte_position (ptr_field);
-
-  return tree_int_cst_equal (ref_offset, fld_offset) ? rec : NULL_TREE;
-}
-
-/* If STMT looks like a statement loading a value from a member pointer formal
-   parameter, this function returns that parameter.  */
-
-static tree
-ipa_get_stmt_member_ptr_load_param (gimple stmt, bool use_delta)
-{
-  tree rhs;
-
-  if (!gimple_assign_single_p (stmt))
-    return NULL_TREE;
-
-  rhs = gimple_assign_rhs1 (stmt);
-  return ipa_get_member_ptr_load_param (rhs, use_delta);
+    return tree_int_cst_equal (byte_position (fld), ref_offset) ? rec
+      : NULL_TREE;
 }
 
 /* Returns true iff T is an SSA_NAME defined by a statement.  */
 }
 
 /* Returns true iff T is an SSA_NAME defined by a statement.  */
@@ -1205,13 +1569,14 @@ ipa_note_param_call (struct cgraph_node *node, int param_index, gimple stmt)
 
   cs = cgraph_edge (node, stmt);
   cs->indirect_info->param_index = param_index;
 
   cs = cgraph_edge (node, stmt);
   cs->indirect_info->param_index = param_index;
-  cs->indirect_info->anc_offset = 0;
+  cs->indirect_info->offset = 0;
   cs->indirect_info->polymorphic = 0;
   cs->indirect_info->polymorphic = 0;
+  cs->indirect_info->agg_contents = 0;
   return cs;
 }
 
 /* Analyze the CALL and examine uses of formal parameters of the caller NODE
   return cs;
 }
 
 /* Analyze the CALL and examine uses of formal parameters of the caller NODE
-   (described by INFO).  PARMS_INFO is a pointer to a vector containing
+   (described by INFO).  PARMS_AINFO is a pointer to a vector containing
    intermediate information about each formal parameter.  Currently it checks
    whether the call calls a pointer that is a formal parameter and if so, the
    parameter is marked with the called flag and an indirect call graph edge
    intermediate information about each formal parameter.  Currently it checks
    whether the call calls a pointer that is a formal parameter and if so, the
    parameter is marked with the called flag and an indirect call graph edge
@@ -1265,12 +1630,14 @@ ipa_note_param_call (struct cgraph_node *node, int param_index, gimple stmt)
 
        return (S.*f)(4);
      }
 
        return (S.*f)(4);
      }
-*/
+
+   Moreover, the function also looks for called pointers loaded from aggregates
+   passed by value or reference.  */
 
 static void
 ipa_analyze_indirect_call_uses (struct cgraph_node *node,
                                struct ipa_node_params *info,
 
 static void
 ipa_analyze_indirect_call_uses (struct cgraph_node *node,
                                struct ipa_node_params *info,
-                               struct param_analysis_info *parms_info,
+                               struct param_analysis_info *parms_ainfo,
                                gimple call, tree target)
 {
   gimple def;
                                gimple call, tree target)
 {
   gimple def;
@@ -1280,6 +1647,8 @@ ipa_analyze_indirect_call_uses (struct cgraph_node *node,
   gimple branch;
   int index;
   basic_block bb, virt_bb, join;
   gimple branch;
   int index;
   basic_block bb, virt_bb, join;
+  HOST_WIDE_INT offset;
+  bool by_ref;
 
   if (SSA_NAME_IS_DEFAULT_DEF (target))
     {
 
   if (SSA_NAME_IS_DEFAULT_DEF (target))
     {
@@ -1290,20 +1659,27 @@ ipa_analyze_indirect_call_uses (struct cgraph_node *node,
       return;
     }
 
       return;
     }
 
+  def = SSA_NAME_DEF_STMT (target);
+  if (gimple_assign_single_p (def)
+      && ipa_load_from_parm_agg_1 (info->descriptors, parms_ainfo, def,
+                                  gimple_assign_rhs1 (def), &index, &offset,
+                                  &by_ref))
+    {
+      struct cgraph_edge *cs = ipa_note_param_call (node, index, call);
+      cs->indirect_info->offset = offset;
+      cs->indirect_info->agg_contents = 1;
+      cs->indirect_info->by_ref = by_ref;
+      return;
+    }
+
   /* Now we need to try to match the complex pattern of calling a member
      pointer. */
   /* Now we need to try to match the complex pattern of calling a member
      pointer. */
-
-  if (!POINTER_TYPE_P (TREE_TYPE (target))
+  if (gimple_code (def) != GIMPLE_PHI
+      || gimple_phi_num_args (def) != 2
+      || !POINTER_TYPE_P (TREE_TYPE (target))
       || TREE_CODE (TREE_TYPE (TREE_TYPE (target))) != METHOD_TYPE)
     return;
 
       || TREE_CODE (TREE_TYPE (TREE_TYPE (target))) != METHOD_TYPE)
     return;
 
-  def = SSA_NAME_DEF_STMT (target);
-  if (gimple_code (def) != GIMPLE_PHI)
-    return;
-
-  if (gimple_phi_num_args (def) != 2)
-    return;
-
   /* First, we need to check whether one of these is a load from a member
      pointer that is a parameter to this function. */
   n1 = PHI_ARG_DEF (def, 0);
   /* First, we need to check whether one of these is a load from a member
      pointer that is a parameter to this function. */
   n1 = PHI_ARG_DEF (def, 0);
@@ -1314,15 +1690,15 @@ ipa_analyze_indirect_call_uses (struct cgraph_node *node,
   d2 = SSA_NAME_DEF_STMT (n2);
 
   join = gimple_bb (def);
   d2 = SSA_NAME_DEF_STMT (n2);
 
   join = gimple_bb (def);
-  if ((rec = ipa_get_stmt_member_ptr_load_param (d1, false)))
+  if ((rec = ipa_get_stmt_member_ptr_load_param (d1, false, &offset)))
     {
     {
-      if (ipa_get_stmt_member_ptr_load_param (d2, false))
+      if (ipa_get_stmt_member_ptr_load_param (d2, false, NULL))
        return;
 
       bb = EDGE_PRED (join, 0)->src;
       virt_bb = gimple_bb (d2);
     }
        return;
 
       bb = EDGE_PRED (join, 0)->src;
       virt_bb = gimple_bb (d2);
     }
-  else if ((rec = ipa_get_stmt_member_ptr_load_param (d2, false)))
+  else if ((rec = ipa_get_stmt_member_ptr_load_param (d2, false, &offset)))
     {
       bb = EDGE_PRED (join, 1)->src;
       virt_bb = gimple_bb (d1);
     {
       bb = EDGE_PRED (join, 1)->src;
       virt_bb = gimple_bb (d1);
@@ -1345,7 +1721,8 @@ ipa_analyze_indirect_call_uses (struct cgraph_node *node,
   if (!branch || gimple_code (branch) != GIMPLE_COND)
     return;
 
   if (!branch || gimple_code (branch) != GIMPLE_COND)
     return;
 
-  if (gimple_cond_code (branch) != NE_EXPR
+  if ((gimple_cond_code (branch) != NE_EXPR
+       && gimple_cond_code (branch) != EQ_EXPR)
       || !integer_zerop (gimple_cond_rhs (branch)))
     return;
 
       || !integer_zerop (gimple_cond_rhs (branch)))
     return;
 
@@ -1376,15 +1753,19 @@ ipa_analyze_indirect_call_uses (struct cgraph_node *node,
 
   rec2 = ipa_get_stmt_member_ptr_load_param (def,
                                             (TARGET_PTRMEMFUNC_VBIT_LOCATION
 
   rec2 = ipa_get_stmt_member_ptr_load_param (def,
                                             (TARGET_PTRMEMFUNC_VBIT_LOCATION
-                                             == ptrmemfunc_vbit_in_delta));
-
+                                             == ptrmemfunc_vbit_in_delta),
+                                            NULL);
   if (rec != rec2)
     return;
 
   index = ipa_get_param_decl_index (info, rec);
   if (rec != rec2)
     return;
 
   index = ipa_get_param_decl_index (info, rec);
-  if (index >= 0 && !is_parm_modified_before_call (&parms_info[index],
-                                                  call, rec))
-    ipa_note_param_call (node, index, call);
+  if (index >= 0
+      && parm_preserved_before_stmt_p (&parms_ainfo[index], call, rec))
+    {
+      struct cgraph_edge *cs = ipa_note_param_call (node, index, call);
+      cs->indirect_info->offset = offset;
+      cs->indirect_info->agg_contents = 1;
+    }
 
   return;
 }
 
   return;
 }
@@ -1439,27 +1820,27 @@ ipa_analyze_virtual_call_uses (struct cgraph_node *node,
 
   cs = ipa_note_param_call (node, index, call);
   ii = cs->indirect_info;
 
   cs = ipa_note_param_call (node, index, call);
   ii = cs->indirect_info;
-  ii->anc_offset = anc_offset;
+  ii->offset = anc_offset;
   ii->otr_token = tree_low_cst (OBJ_TYPE_REF_TOKEN (target), 1);
   ii->otr_type = TREE_TYPE (TREE_TYPE (OBJ_TYPE_REF_OBJECT (target)));
   ii->polymorphic = 1;
 }
 
 /* Analyze a call statement CALL whether and how it utilizes formal parameters
   ii->otr_token = tree_low_cst (OBJ_TYPE_REF_TOKEN (target), 1);
   ii->otr_type = TREE_TYPE (TREE_TYPE (OBJ_TYPE_REF_OBJECT (target)));
   ii->polymorphic = 1;
 }
 
 /* Analyze a call statement CALL whether and how it utilizes formal parameters
-   of the caller (described by INFO).  PARMS_INFO is a pointer to a vector
+   of the caller (described by INFO).  PARMS_AINFO is a pointer to a vector
    containing intermediate information about each formal parameter.  */
 
 static void
 ipa_analyze_call_uses (struct cgraph_node *node,
                       struct ipa_node_params *info,
    containing intermediate information about each formal parameter.  */
 
 static void
 ipa_analyze_call_uses (struct cgraph_node *node,
                       struct ipa_node_params *info,
-                      struct param_analysis_info *parms_info, gimple call)
+                      struct param_analysis_info *parms_ainfo, gimple call)
 {
   tree target = gimple_call_fn (call);
 
   if (!target)
     return;
   if (TREE_CODE (target) == SSA_NAME)
 {
   tree target = gimple_call_fn (call);
 
   if (!target)
     return;
   if (TREE_CODE (target) == SSA_NAME)
-    ipa_analyze_indirect_call_uses (node, info, parms_info, call, target);
+    ipa_analyze_indirect_call_uses (node, info, parms_ainfo, call, target);
   else if (TREE_CODE (target) == OBJ_TYPE_REF)
     ipa_analyze_virtual_call_uses (node, info, call, target);
 }
   else if (TREE_CODE (target) == OBJ_TYPE_REF)
     ipa_analyze_virtual_call_uses (node, info, call, target);
 }
@@ -1467,15 +1848,15 @@ ipa_analyze_call_uses (struct cgraph_node *node,
 
 /* Analyze the call statement STMT with respect to formal parameters (described
    in INFO) of caller given by NODE.  Currently it only checks whether formal
 
 /* Analyze the call statement STMT with respect to formal parameters (described
    in INFO) of caller given by NODE.  Currently it only checks whether formal
-   parameters are called.  PARMS_INFO is a pointer to a vector containing
+   parameters are called.  PARMS_AINFO is a pointer to a vector containing
    intermediate information about each formal parameter.  */
 
 static void
 ipa_analyze_stmt_uses (struct cgraph_node *node, struct ipa_node_params *info,
    intermediate information about each formal parameter.  */
 
 static void
 ipa_analyze_stmt_uses (struct cgraph_node *node, struct ipa_node_params *info,
-                      struct param_analysis_info *parms_info, gimple stmt)
+                      struct param_analysis_info *parms_ainfo, gimple stmt)
 {
   if (is_gimple_call (stmt))
 {
   if (is_gimple_call (stmt))
-    ipa_analyze_call_uses (node, info, parms_info, stmt);
+    ipa_analyze_call_uses (node, info, parms_ainfo, stmt);
 }
 
 /* Callback of walk_stmt_load_store_addr_ops for the visit_load.
 }
 
 /* Callback of walk_stmt_load_store_addr_ops for the visit_load.
@@ -1494,7 +1875,7 @@ visit_ref_for_mod_analysis (gimple stmt ATTRIBUTE_UNUSED,
     {
       int index = ipa_get_param_decl_index (info, op);
       gcc_assert (index >= 0);
     {
       int index = ipa_get_param_decl_index (info, op);
       gcc_assert (index >= 0);
-      info->params[index].used = true;
+      ipa_set_param_used (info, index, true);
     }
 
   return false;
     }
 
   return false;
@@ -1502,14 +1883,14 @@ visit_ref_for_mod_analysis (gimple stmt ATTRIBUTE_UNUSED,
 
 /* Scan the function body of NODE and inspect the uses of formal parameters.
    Store the findings in various structures of the associated ipa_node_params
 
 /* Scan the function body of NODE and inspect the uses of formal parameters.
    Store the findings in various structures of the associated ipa_node_params
-   structure, such as parameter flags, notes etc.  PARMS_INFO is a pointer to a
+   structure, such as parameter flags, notes etc.  PARMS_AINFO is a pointer to a
    vector containing intermediate information about each formal parameter.   */
 
 static void
 ipa_analyze_params_uses (struct cgraph_node *node,
    vector containing intermediate information about each formal parameter.   */
 
 static void
 ipa_analyze_params_uses (struct cgraph_node *node,
-                        struct param_analysis_info *parms_info)
+                        struct param_analysis_info *parms_ainfo)
 {
 {
-  tree decl = node->decl;
+  tree decl = node->symbol.decl;
   basic_block bb;
   struct function *func;
   gimple_stmt_iterator gsi;
   basic_block bb;
   struct function *func;
   gimple_stmt_iterator gsi;
@@ -1522,11 +1903,14 @@ ipa_analyze_params_uses (struct cgraph_node *node,
   for (i = 0; i < ipa_get_param_count (info); i++)
     {
       tree parm = ipa_get_param (info, i);
   for (i = 0; i < ipa_get_param_count (info); i++)
     {
       tree parm = ipa_get_param (info, i);
+      tree ddef;
       /* For SSA regs see if parameter is used.  For non-SSA we compute
         the flag during modification analysis.  */
       if (is_gimple_reg (parm)
       /* For SSA regs see if parameter is used.  For non-SSA we compute
         the flag during modification analysis.  */
       if (is_gimple_reg (parm)
-         && gimple_default_def (DECL_STRUCT_FUNCTION (node->decl), parm))
-       info->params[i].used = true;
+         && (ddef = ssa_default_def (DECL_STRUCT_FUNCTION (node->symbol.decl),
+                                     parm)) != NULL_TREE
+         && !has_zero_uses (ddef))
+       ipa_set_param_used (info, i, true);
     }
 
   func = DECL_STRUCT_FUNCTION (decl);
     }
 
   func = DECL_STRUCT_FUNCTION (decl);
@@ -1539,13 +1923,13 @@ ipa_analyze_params_uses (struct cgraph_node *node,
          if (is_gimple_debug (stmt))
            continue;
 
          if (is_gimple_debug (stmt))
            continue;
 
-         ipa_analyze_stmt_uses (node, info, parms_info, stmt);
+         ipa_analyze_stmt_uses (node, info, parms_ainfo, stmt);
          walk_stmt_load_store_addr_ops (stmt, info,
                                         visit_ref_for_mod_analysis,
                                         visit_ref_for_mod_analysis,
                                         visit_ref_for_mod_analysis);
        }
          walk_stmt_load_store_addr_ops (stmt, info,
                                         visit_ref_for_mod_analysis,
                                         visit_ref_for_mod_analysis,
                                         visit_ref_for_mod_analysis);
        }
-      for (gsi = gsi_start (phi_nodes (bb)); !gsi_end_p (gsi); gsi_next (&gsi))
+      for (gsi = gsi_start_phis (bb); !gsi_end_p (gsi); gsi_next (&gsi))
        walk_stmt_load_store_addr_ops (gsi_stmt (gsi), info,
                                       visit_ref_for_mod_analysis,
                                       visit_ref_for_mod_analysis,
        walk_stmt_load_store_addr_ops (gsi_stmt (gsi), info,
                                       visit_ref_for_mod_analysis,
                                       visit_ref_for_mod_analysis,
@@ -1555,6 +1939,22 @@ ipa_analyze_params_uses (struct cgraph_node *node,
   info->uses_analysis_done = 1;
 }
 
   info->uses_analysis_done = 1;
 }
 
+/* Free stuff in PARMS_AINFO, assume there are PARAM_COUNT parameters.  */
+
+static void
+free_parms_ainfo (struct param_analysis_info *parms_ainfo, int param_count)
+{
+  int i;
+
+  for (i = 0; i < param_count; i++)
+    {
+      if (parms_ainfo[i].parm_visited_statements)
+       BITMAP_FREE (parms_ainfo[i].parm_visited_statements);
+      if (parms_ainfo[i].pt_visited_statements)
+       BITMAP_FREE (parms_ainfo[i].pt_visited_statements);
+    }
+}
+
 /* Initialize the array describing properties of of formal parameters
    of NODE, analyze their uses and compute jump functions associated
    with actual arguments of calls from within NODE.  */
 /* Initialize the array describing properties of of formal parameters
    of NODE, analyze their uses and compute jump functions associated
    with actual arguments of calls from within NODE.  */
@@ -1563,28 +1963,23 @@ void
 ipa_analyze_node (struct cgraph_node *node)
 {
   struct ipa_node_params *info;
 ipa_analyze_node (struct cgraph_node *node)
 {
   struct ipa_node_params *info;
-  struct param_analysis_info *parms_info;
-  int i, param_count;
+  struct param_analysis_info *parms_ainfo;
+  int param_count;
 
   ipa_check_create_node_params ();
   ipa_check_create_edge_args ();
   info = IPA_NODE_REF (node);
 
   ipa_check_create_node_params ();
   ipa_check_create_edge_args ();
   info = IPA_NODE_REF (node);
-  push_cfun (DECL_STRUCT_FUNCTION (node->decl));
-  current_function_decl = node->decl;
+  push_cfun (DECL_STRUCT_FUNCTION (node->symbol.decl));
   ipa_initialize_node_params (node);
 
   param_count = ipa_get_param_count (info);
   ipa_initialize_node_params (node);
 
   param_count = ipa_get_param_count (info);
-  parms_info = XALLOCAVEC (struct param_analysis_info, param_count);
-  memset (parms_info, 0, sizeof (struct param_analysis_info) * param_count);
+  parms_ainfo = XALLOCAVEC (struct param_analysis_info, param_count);
+  memset (parms_ainfo, 0, sizeof (struct param_analysis_info) * param_count);
 
 
-  ipa_analyze_params_uses (node, parms_info);
-  ipa_compute_jump_functions (node, parms_info);
-
-  for (i = 0; i < param_count; i++)
-    if (parms_info[i].visited_statements)
-      BITMAP_FREE (parms_info[i].visited_statements);
+  ipa_analyze_params_uses (node, parms_ainfo);
+  ipa_compute_jump_functions (node, parms_ainfo);
 
 
-  current_function_decl = NULL;
+  free_parms_ainfo (parms_ainfo, param_count);
   pop_cfun ();
 }
 
   pop_cfun ();
 }
 
@@ -1597,18 +1992,16 @@ static void
 combine_known_type_and_ancestor_jfs (struct ipa_jump_func *src,
                                     struct ipa_jump_func *dst)
 {
 combine_known_type_and_ancestor_jfs (struct ipa_jump_func *src,
                                     struct ipa_jump_func *dst)
 {
-  tree new_binfo;
+  HOST_WIDE_INT combined_offset;
+  tree combined_type;
 
 
-  new_binfo = get_binfo_at_offset (src->value.base_binfo,
-                                  dst->value.ancestor.offset,
-                                  dst->value.ancestor.type);
-  if (new_binfo)
-    {
-      dst->type = IPA_JF_KNOWN_TYPE;
-      dst->value.base_binfo = new_binfo;
-    }
-  else
-    dst->type = IPA_JF_UNKNOWN;
+  combined_offset = ipa_get_jf_known_type_offset (src)
+    + ipa_get_jf_ancestor_offset (dst);
+  combined_type = ipa_get_jf_ancestor_type (dst);
+
+  ipa_set_jf_known_type (dst, combined_offset,
+                        ipa_get_jf_known_type_base_type (src),
+                        combined_type);
 }
 
 /* Update the jump functions associated with call graph edge E when the call
 }
 
 /* Update the jump functions associated with call graph edge E when the call
@@ -1631,26 +2024,50 @@ update_jump_functions_after_inlining (struct cgraph_edge *cs,
       if (dst->type == IPA_JF_ANCESTOR)
        {
          struct ipa_jump_func *src;
       if (dst->type == IPA_JF_ANCESTOR)
        {
          struct ipa_jump_func *src;
+         int dst_fid = dst->value.ancestor.formal_id;
 
          /* Variable number of arguments can cause havoc if we try to access
             one that does not exist in the inlined edge.  So make sure we
             don't.  */
 
          /* Variable number of arguments can cause havoc if we try to access
             one that does not exist in the inlined edge.  So make sure we
             don't.  */
-         if (dst->value.ancestor.formal_id >= ipa_get_cs_argument_count (top))
+         if (dst_fid >= ipa_get_cs_argument_count (top))
            {
              dst->type = IPA_JF_UNKNOWN;
              continue;
            }
 
            {
              dst->type = IPA_JF_UNKNOWN;
              continue;
            }
 
-         src = ipa_get_ith_jump_func (top, dst->value.ancestor.formal_id);
+         src = ipa_get_ith_jump_func (top, dst_fid);
+
+         if (src->agg.items
+             && (dst->value.ancestor.agg_preserved || !src->agg.by_ref))
+           {
+             struct ipa_agg_jf_item *item;
+             int j;
+
+             /* Currently we do not produce clobber aggregate jump functions,
+                replace with merging when we do.  */
+             gcc_assert (!dst->agg.items);
+
+             dst->agg.items = vec_safe_copy (src->agg.items);
+             dst->agg.by_ref = src->agg.by_ref;
+             FOR_EACH_VEC_SAFE_ELT (dst->agg.items, j, item)
+               item->offset -= dst->value.ancestor.offset;
+           }
+
          if (src->type == IPA_JF_KNOWN_TYPE)
            combine_known_type_and_ancestor_jfs (src, dst);
          else if (src->type == IPA_JF_PASS_THROUGH
                   && src->value.pass_through.operation == NOP_EXPR)
          if (src->type == IPA_JF_KNOWN_TYPE)
            combine_known_type_and_ancestor_jfs (src, dst);
          else if (src->type == IPA_JF_PASS_THROUGH
                   && src->value.pass_through.operation == NOP_EXPR)
-           dst->value.ancestor.formal_id = src->value.pass_through.formal_id;
+           {
+             dst->value.ancestor.formal_id = src->value.pass_through.formal_id;
+             dst->value.ancestor.agg_preserved &=
+               src->value.pass_through.agg_preserved;
+           }
          else if (src->type == IPA_JF_ANCESTOR)
            {
              dst->value.ancestor.formal_id = src->value.ancestor.formal_id;
              dst->value.ancestor.offset += src->value.ancestor.offset;
          else if (src->type == IPA_JF_ANCESTOR)
            {
              dst->value.ancestor.formal_id = src->value.ancestor.formal_id;
              dst->value.ancestor.offset += src->value.ancestor.offset;
+             dst->value.ancestor.agg_preserved &=
+               src->value.ancestor.agg_preserved;
            }
          else
            dst->type = IPA_JF_UNKNOWN;
            }
          else
            dst->type = IPA_JF_UNKNOWN;
@@ -1664,9 +2081,32 @@ update_jump_functions_after_inlining (struct cgraph_edge *cs,
              && (dst->value.pass_through.formal_id
                  < ipa_get_cs_argument_count (top)))
            {
              && (dst->value.pass_through.formal_id
                  < ipa_get_cs_argument_count (top)))
            {
-             src = ipa_get_ith_jump_func (top,
-                                          dst->value.pass_through.formal_id);
-             *dst = *src;
+             bool agg_p;
+             int dst_fid = dst->value.pass_through.formal_id;
+             src = ipa_get_ith_jump_func (top, dst_fid);
+             agg_p = dst->value.pass_through.agg_preserved;
+
+             dst->type = src->type;
+             dst->value = src->value;
+
+             if (src->agg.items
+                 && (agg_p || !src->agg.by_ref))
+               {
+                 /* Currently we do not produce clobber aggregate jump
+                    functions, replace with merging when we do.  */
+                 gcc_assert (!dst->agg.items);
+
+                 dst->agg.by_ref = src->agg.by_ref;
+                 dst->agg.items = vec_safe_copy (src->agg.items);
+               }
+
+             if (!agg_p)
+               {
+                 if (dst->type == IPA_JF_PASS_THROUGH)
+                   dst->value.pass_through.agg_preserved = false;
+                 else if (dst->type == IPA_JF_ANCESTOR)
+                   dst->value.ancestor.agg_preserved = false;
+               }
            }
          else
            dst->type = IPA_JF_UNKNOWN;
            }
          else
            dst->type = IPA_JF_UNKNOWN;
@@ -1675,14 +2115,13 @@ update_jump_functions_after_inlining (struct cgraph_edge *cs,
 }
 
 /* If TARGET is an addr_expr of a function declaration, make it the destination
 }
 
 /* If TARGET is an addr_expr of a function declaration, make it the destination
-   of an indirect edge IE and return the edge.  Otherwise, return NULL.  Delta,
-   if non-NULL, is an integer constant that must be added to this pointer
-   (first parameter).  */
+   of an indirect edge IE and return the edge.  Otherwise, return NULL.  */
 
 struct cgraph_edge *
 
 struct cgraph_edge *
-ipa_make_edge_direct_to_target (struct cgraph_edge *ie, tree target, tree delta)
+ipa_make_edge_direct_to_target (struct cgraph_edge *ie, tree target)
 {
   struct cgraph_node *callee;
 {
   struct cgraph_node *callee;
+  struct inline_edge_summary *es = inline_edge_summary (ie);
 
   if (TREE_CODE (target) == ADDR_EXPR)
     target = TREE_OPERAND (target, 0);
 
   if (TREE_CODE (target) == ADDR_EXPR)
     target = TREE_OPERAND (target, 0);
@@ -1693,89 +2132,110 @@ ipa_make_edge_direct_to_target (struct cgraph_edge *ie, tree target, tree delta)
     return NULL;
   ipa_check_create_node_params ();
 
     return NULL;
   ipa_check_create_node_params ();
 
-  /* We can not make edges to inline clones.  It is bug that someone removed the cgraph
-     node too early.  */
+  /* We can not 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->global.inlined_to);
 
-  cgraph_make_edge_direct (ie, callee, delta ? tree_low_cst (delta, 0) : 0);
+  cgraph_make_edge_direct (ie, callee);
+  es = inline_edge_summary (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
+                        - eni_time_weights.call_cost);
   if (dump_file)
     {
       fprintf (dump_file, "ipa-prop: Discovered %s call to a known target "
               "(%s/%i -> %s/%i), for stmt ",
               ie->indirect_info->polymorphic ? "a virtual" : "an indirect",
   if (dump_file)
     {
       fprintf (dump_file, "ipa-prop: Discovered %s call to a known target "
               "(%s/%i -> %s/%i), for stmt ",
               ie->indirect_info->polymorphic ? "a virtual" : "an indirect",
-              cgraph_node_name (ie->caller), ie->caller->uid,
-              cgraph_node_name (ie->callee), ie->callee->uid);
+              xstrdup (cgraph_node_name (ie->caller)), ie->caller->uid,
+              xstrdup (cgraph_node_name (ie->callee)), ie->callee->uid);
       if (ie->call_stmt)
        print_gimple_stmt (dump_file, ie->call_stmt, 2, TDF_SLIM);
       else
        fprintf (dump_file, "with uid %i\n", ie->lto_stmt_uid);
       if (ie->call_stmt)
        print_gimple_stmt (dump_file, ie->call_stmt, 2, TDF_SLIM);
       else
        fprintf (dump_file, "with uid %i\n", ie->lto_stmt_uid);
-
-      if (delta)
-       {
-         fprintf (dump_file, "          Thunk delta is ");
-         print_generic_expr (dump_file, delta, 0);
-         fprintf (dump_file, "\n");
-       }
     }
     }
-
-  if (ipa_get_cs_argument_count (IPA_EDGE_REF (ie))
-      != ipa_get_param_count (IPA_NODE_REF (callee)))
-    ipa_set_called_with_variable_arg (IPA_NODE_REF (callee));
+  callee = cgraph_function_or_thunk_node (callee, NULL);
 
   return ie;
 }
 
 
   return ie;
 }
 
+/* Retrieve value from aggregate jump function AGG for the given OFFSET or
+   return NULL if there is not any.  BY_REF specifies whether the value has to
+   be passed by reference or by value.  */
+
+tree
+ipa_find_agg_cst_for_param (struct ipa_agg_jump_function *agg,
+                           HOST_WIDE_INT offset, bool by_ref)
+{
+  struct ipa_agg_jf_item *item;
+  int i;
+
+  if (by_ref != agg->by_ref)
+    return NULL;
+
+  FOR_EACH_VEC_SAFE_ELT (agg->items, i, item)
+    if (item->offset == offset)
+      {
+       /* Currently we do not have clobber values, return NULL for them once
+          we do.  */
+       gcc_checking_assert (is_gimple_ip_invariant (item->value));
+       return item->value;
+      }
+  return NULL;
+}
+
 /* 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
 /* 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.  */
+   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,
 
 static struct cgraph_edge *
 try_make_edge_direct_simple_call (struct cgraph_edge *ie,
-                                 struct ipa_jump_func *jfunc)
+                                 struct ipa_jump_func *jfunc,
+                                 struct ipa_node_params *new_root_info)
 {
   tree target;
 
 {
   tree target;
 
-  if (jfunc->type == IPA_JF_CONST)
-    target = jfunc->value.constant;
-  else if (jfunc->type == IPA_JF_CONST_MEMBER_PTR)
-    target = jfunc->value.member_cst.pfn;
+  if (ie->indirect_info->agg_contents)
+    target = ipa_find_agg_cst_for_param (&jfunc->agg,
+                                        ie->indirect_info->offset,
+                                        ie->indirect_info->by_ref);
   else
   else
+    target = ipa_value_from_jfunc (new_root_info, jfunc);
+  if (!target)
     return NULL;
     return NULL;
-
-  return ipa_make_edge_direct_to_target (ie, target, NULL_TREE);
+  return ipa_make_edge_direct_to_target (ie, target);
 }
 
 }
 
-/* Try to find a destination for indirect edge IE that corresponds to a
-   virtual 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.  */
+/* Try to find a destination for indirect edge IE that corresponds to a virtual
+   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.  NEW_ROOT_INFO is the node info that JFUNC lattices
+   are relative to.  */
 
 static struct cgraph_edge *
 try_make_edge_direct_virtual_call (struct cgraph_edge *ie,
 
 static struct cgraph_edge *
 try_make_edge_direct_virtual_call (struct cgraph_edge *ie,
-                                  struct ipa_jump_func *jfunc)
+                                  struct ipa_jump_func *jfunc,
+                                  struct ipa_node_params *new_root_info)
 {
 {
-  tree binfo, type, target, delta;
-  HOST_WIDE_INT token;
+  tree binfo, target;
 
 
-  if (jfunc->type == IPA_JF_KNOWN_TYPE)
-    binfo = jfunc->value.base_binfo;
-  else
-    return NULL;
+  binfo = ipa_value_from_jfunc (new_root_info, jfunc);
 
 
-  if (!binfo)
+  if (!binfo || TREE_CODE (binfo) != TREE_BINFO)
     return NULL;
 
     return NULL;
 
-  token = ie->indirect_info->otr_token;
-  type = ie->indirect_info->otr_type;
-  binfo = get_binfo_at_offset (binfo, ie->indirect_info->anc_offset, type);
+  binfo = get_binfo_at_offset (binfo, ie->indirect_info->offset,
+                              ie->indirect_info->otr_type);
   if (binfo)
   if (binfo)
-    target = gimple_get_virt_method_for_binfo (token, binfo, &delta, true);
+    target = gimple_get_virt_method_for_binfo (ie->indirect_info->otr_token,
+                                              binfo);
   else
     return NULL;
 
   if (target)
   else
     return NULL;
 
   if (target)
-    return ipa_make_edge_direct_to_target (ie, target, delta);
+    return ipa_make_edge_direct_to_target (ie, target);
   else
     return NULL;
 }
   else
     return NULL;
 }
@@ -1789,61 +2249,83 @@ try_make_edge_direct_virtual_call (struct cgraph_edge *ie,
 static bool
 update_indirect_edges_after_inlining (struct cgraph_edge *cs,
                                      struct cgraph_node *node,
 static bool
 update_indirect_edges_after_inlining (struct cgraph_edge *cs,
                                      struct cgraph_node *node,
-                                     VEC (cgraph_edge_p, heap) **new_edges)
+                                     vec<cgraph_edge_p> *new_edges)
 {
   struct ipa_edge_args *top;
   struct cgraph_edge *ie, *next_ie, *new_direct_edge;
 {
   struct ipa_edge_args *top;
   struct cgraph_edge *ie, *next_ie, *new_direct_edge;
+  struct ipa_node_params *new_root_info;
   bool res = false;
 
   ipa_check_create_edge_args ();
   top = IPA_EDGE_REF (cs);
   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);
 
   for (ie = node->indirect_calls; ie; ie = next_ie)
     {
       struct cgraph_indirect_call_info *ici = ie->indirect_info;
       struct ipa_jump_func *jfunc;
 
   for (ie = node->indirect_calls; ie; ie = next_ie)
     {
       struct cgraph_indirect_call_info *ici = ie->indirect_info;
       struct ipa_jump_func *jfunc;
+      int param_index;
 
       next_ie = ie->next_callee;
 
       next_ie = ie->next_callee;
-      if (bitmap_bit_p (iinlining_processed_edges, ie->uid))
-       continue;
 
 
-      /* If we ever use indirect edges for anything other than indirect
-        inlining, we will need to skip those with negative param_indices. */
       if (ici->param_index == -1)
        continue;
 
       /* We must check range due to calls with variable number of arguments:  */
       if (ici->param_index >= ipa_get_cs_argument_count (top))
        {
       if (ici->param_index == -1)
        continue;
 
       /* We must check range due to calls with variable number of arguments:  */
       if (ici->param_index >= ipa_get_cs_argument_count (top))
        {
-         bitmap_set_bit (iinlining_processed_edges, ie->uid);
+         ici->param_index = -1;
          continue;
        }
 
          continue;
        }
 
-      jfunc = ipa_get_ith_jump_func (top, ici->param_index);
+      param_index = ici->param_index;
+      jfunc = ipa_get_ith_jump_func (top, param_index);
       if (jfunc->type == IPA_JF_PASS_THROUGH
       if (jfunc->type == IPA_JF_PASS_THROUGH
-         && jfunc->value.pass_through.operation == NOP_EXPR)
-       ici->param_index = jfunc->value.pass_through.formal_id;
+         && ipa_get_jf_pass_through_operation (jfunc) == NOP_EXPR)
+       {
+         if (ici->agg_contents
+             && !ipa_get_jf_pass_through_agg_preserved (jfunc))
+           ici->param_index = -1;
+         else
+           ici->param_index = ipa_get_jf_pass_through_formal_id (jfunc);
+       }
       else if (jfunc->type == IPA_JF_ANCESTOR)
        {
       else if (jfunc->type == IPA_JF_ANCESTOR)
        {
-         ici->param_index = jfunc->value.ancestor.formal_id;
-         ici->anc_offset += jfunc->value.ancestor.offset;
+         if (ici->agg_contents
+             && !ipa_get_jf_ancestor_agg_preserved (jfunc))
+           ici->param_index = -1;
+         else
+           {
+             ici->param_index = ipa_get_jf_ancestor_formal_id (jfunc);
+             ici->offset += ipa_get_jf_ancestor_offset (jfunc);
+           }
        }
       else
        /* Either we can find a destination for this edge now or never. */
        }
       else
        /* Either we can find a destination for this edge now or never. */
-       bitmap_set_bit (iinlining_processed_edges, ie->uid);
+       ici->param_index = -1;
+
+      if (!flag_indirect_inlining)
+       continue;
 
       if (ici->polymorphic)
 
       if (ici->polymorphic)
-       new_direct_edge = try_make_edge_direct_virtual_call (ie, jfunc);
+       new_direct_edge = try_make_edge_direct_virtual_call (ie, jfunc,
+                                                            new_root_info);
       else
       else
-       new_direct_edge = try_make_edge_direct_simple_call (ie, jfunc);
+       new_direct_edge = try_make_edge_direct_simple_call (ie, jfunc,
+                                                           new_root_info);
 
       if (new_direct_edge)
        {
          new_direct_edge->indirect_inlining_edge = 1;
 
       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->symbol.decl);
          if (new_edges)
            {
          if (new_edges)
            {
-             VEC_safe_push (cgraph_edge_p, heap, *new_edges,
-                            new_direct_edge);
+             new_edges->safe_push (new_direct_edge);
              top = IPA_EDGE_REF (cs);
              res = true;
            }
              top = IPA_EDGE_REF (cs);
              res = true;
            }
@@ -1864,7 +2346,7 @@ update_indirect_edges_after_inlining (struct cgraph_edge *cs,
 static bool
 propagate_info_to_inlined_callees (struct cgraph_edge *cs,
                                   struct cgraph_node *node,
 static bool
 propagate_info_to_inlined_callees (struct cgraph_edge *cs,
                                   struct cgraph_node *node,
-                                  VEC (cgraph_edge_p, heap) **new_edges)
+                                  vec<cgraph_edge_p> *new_edges)
 {
   struct cgraph_edge *e;
   bool res;
 {
   struct cgraph_edge *e;
   bool res;
@@ -1876,6 +2358,8 @@ propagate_info_to_inlined_callees (struct cgraph_edge *cs,
       res |= propagate_info_to_inlined_callees (cs, e->callee, new_edges);
     else
       update_jump_functions_after_inlining (cs, e);
       res |= propagate_info_to_inlined_callees (cs, e->callee, new_edges);
     else
       update_jump_functions_after_inlining (cs, e);
+  for (e = node->indirect_calls; e; e = e->next_callee)
+    update_jump_functions_after_inlining (cs, e);
 
   return res;
 }
 
   return res;
 }
@@ -1888,19 +2372,21 @@ propagate_info_to_inlined_callees (struct cgraph_edge *cs,
 
 bool
 ipa_propagate_indirect_call_infos (struct cgraph_edge *cs,
 
 bool
 ipa_propagate_indirect_call_infos (struct cgraph_edge *cs,
-                                  VEC (cgraph_edge_p, heap) **new_edges)
+                                  vec<cgraph_edge_p> *new_edges)
 {
 {
-  /* FIXME lto: We do not stream out indirect call information.  */
-  if (flag_wpa)
-    return false;
-
+  bool changed;
   /* Do nothing if the preparation phase has not been carried out yet
      (i.e. during early inlining).  */
   /* Do nothing if the preparation phase has not been carried out yet
      (i.e. during early inlining).  */
-  if (!ipa_node_params_vector)
+  if (!ipa_node_params_vector.exists ())
     return false;
   gcc_assert (ipa_edge_args_vector);
 
     return false;
   gcc_assert (ipa_edge_args_vector);
 
-  return propagate_info_to_inlined_callees (cs, cs->callee, new_edges);
+  changed = propagate_info_to_inlined_callees (cs, cs->callee, new_edges);
+
+  /* We do not keep jump functions of inlined edges up to date. Better to free
+     them so we do not access them accidentally.  */
+  ipa_free_edge_args_substructures (IPA_EDGE_REF (cs));
+  return changed;
 }
 
 /* Frees all dynamically allocated structures that the argument info points
 }
 
 /* Frees all dynamically allocated structures that the argument info points
@@ -1909,9 +2395,7 @@ ipa_propagate_indirect_call_infos (struct cgraph_edge *cs,
 void
 ipa_free_edge_args_substructures (struct ipa_edge_args *args)
 {
 void
 ipa_free_edge_args_substructures (struct ipa_edge_args *args)
 {
-  if (args->jump_functions)
-    ggc_free (args->jump_functions);
-
+  vec_free (args->jump_functions);
   memset (args, 0, sizeof (*args));
 }
 
   memset (args, 0, sizeof (*args));
 }
 
@@ -1923,11 +2407,13 @@ ipa_free_all_edge_args (void)
   int i;
   struct ipa_edge_args *args;
 
   int i;
   struct ipa_edge_args *args;
 
-  FOR_EACH_VEC_ELT (ipa_edge_args_t, ipa_edge_args_vector, i, args)
+  if (!ipa_edge_args_vector)
+    return;
+
+  FOR_EACH_VEC_ELT (*ipa_edge_args_vector, i, args)
     ipa_free_edge_args_substructures (args);
 
     ipa_free_edge_args_substructures (args);
 
-  VEC_free (ipa_edge_args_t, gc, ipa_edge_args_vector);
-  ipa_edge_args_vector = NULL;
+  vec_free (ipa_edge_args_vector);
 }
 
 /* Frees all dynamically allocated structures that the param info points
 }
 
 /* Frees all dynamically allocated structures that the param info points
@@ -1936,9 +2422,11 @@ ipa_free_all_edge_args (void)
 void
 ipa_free_node_params_substructures (struct ipa_node_params *info)
 {
 void
 ipa_free_node_params_substructures (struct ipa_node_params *info)
 {
-  if (info->params)
-    free (info->params);
-
+  info->descriptors.release ();
+  free (info->lattices);
+  /* Lattice values and their sources are deallocated with their alocation
+     pool.  */
+  info->known_vals.release ();
   memset (info, 0, sizeof (*info));
 }
 
   memset (info, 0, sizeof (*info));
 }
 
@@ -1950,11 +2438,22 @@ ipa_free_all_node_params (void)
   int i;
   struct ipa_node_params *info;
 
   int i;
   struct ipa_node_params *info;
 
-  FOR_EACH_VEC_ELT (ipa_node_params_t, ipa_node_params_vector, i, info)
+  FOR_EACH_VEC_ELT (ipa_node_params_vector, i, info)
     ipa_free_node_params_substructures (info);
 
     ipa_free_node_params_substructures (info);
 
-  VEC_free (ipa_node_params_t, heap, ipa_node_params_vector);
-  ipa_node_params_vector = NULL;
+  ipa_node_params_vector.release ();
+}
+
+/* Set the aggregate replacements of NODE to be AGGVALS.  */
+
+void
+ipa_set_node_agg_value_chain (struct cgraph_node *node,
+                             struct ipa_agg_replacement_value *aggvals)
+{
+  if (vec_safe_length (ipa_node_agg_replacements) <= (unsigned) cgraph_max_uid)
+    vec_safe_grow_cleared (ipa_node_agg_replacements, cgraph_max_uid + 1);
+
+  (*ipa_node_agg_replacements)[node->uid] = 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.  */
@@ -1963,8 +2462,7 @@ static void
 ipa_edge_removal_hook (struct cgraph_edge *cs, void *data ATTRIBUTE_UNUSED)
 {
   /* During IPA-CP updating we can be called on not-yet analyze clones.  */
 ipa_edge_removal_hook (struct cgraph_edge *cs, void *data ATTRIBUTE_UNUSED)
 {
   /* During IPA-CP updating we can be called on not-yet analyze clones.  */
-  if (VEC_length (ipa_edge_args_t, ipa_edge_args_vector)
-      <= (unsigned)cs->uid)
+  if (vec_safe_length (ipa_edge_args_vector) <= (unsigned)cs->uid)
     return;
   ipa_free_edge_args_substructures (IPA_EDGE_REF (cs));
 }
     return;
   ipa_free_edge_args_substructures (IPA_EDGE_REF (cs));
 }
@@ -1975,63 +2473,31 @@ static void
 ipa_node_removal_hook (struct cgraph_node *node, void *data ATTRIBUTE_UNUSED)
 {
   /* During IPA-CP updating we can be called on not-yet analyze clones.  */
 ipa_node_removal_hook (struct cgraph_node *node, void *data ATTRIBUTE_UNUSED)
 {
   /* During IPA-CP updating we can be called on not-yet analyze clones.  */
-  if (VEC_length (ipa_node_params_t, ipa_node_params_vector)
-      <= (unsigned)node->uid)
-    return;
-  ipa_free_node_params_substructures (IPA_NODE_REF (node));
+  if (ipa_node_params_vector.length () > (unsigned)node->uid)
+    ipa_free_node_params_substructures (IPA_NODE_REF (node));
+  if (vec_safe_length (ipa_node_agg_replacements) > (unsigned)node->uid)
+    (*ipa_node_agg_replacements)[(unsigned)node->uid] = NULL;
 }
 
 }
 
-/* Helper function to duplicate an array of size N that is at SRC and store a
-   pointer to it to DST.  Nothing is done if SRC is NULL.  */
-
-static void *
-duplicate_array (void *src, size_t n)
-{
-  void *p;
-
-  if (!src)
-    return NULL;
-
-  p = xmalloc (n);
-  memcpy (p, src, n);
-  return p;
-}
-
-static struct ipa_jump_func *
-duplicate_ipa_jump_func_array (const struct ipa_jump_func * src, size_t n)
-{
-  struct ipa_jump_func *p;
-
-  if (!src)
-    return NULL;
-
-  p = ggc_alloc_vec_ipa_jump_func (n);
-  memcpy (p, src, n * sizeof (struct ipa_jump_func));
-  return p;
-}
-
-/* Hook that is called by cgraph.c when a node is duplicated.  */
+/* Hook that is called by cgraph.c when an edge is duplicated.  */
 
 static void
 ipa_edge_duplication_hook (struct cgraph_edge *src, struct cgraph_edge *dst,
                           __attribute__((unused)) void *data)
 {
   struct ipa_edge_args *old_args, *new_args;
 
 static void
 ipa_edge_duplication_hook (struct cgraph_edge *src, struct cgraph_edge *dst,
                           __attribute__((unused)) void *data)
 {
   struct ipa_edge_args *old_args, *new_args;
-  int arg_count;
+  unsigned int i;
 
   ipa_check_create_edge_args ();
 
   old_args = IPA_EDGE_REF (src);
   new_args = IPA_EDGE_REF (dst);
 
 
   ipa_check_create_edge_args ();
 
   old_args = IPA_EDGE_REF (src);
   new_args = IPA_EDGE_REF (dst);
 
-  arg_count = ipa_get_cs_argument_count (old_args);
-  ipa_set_cs_argument_count (new_args, arg_count);
-  new_args->jump_functions =
-    duplicate_ipa_jump_func_array (old_args->jump_functions, arg_count);
+  new_args->jump_functions = vec_safe_copy (old_args->jump_functions);
 
 
-  if (iinlining_processed_edges
-      && bitmap_bit_p (iinlining_processed_edges, src->uid))
-    bitmap_set_bit (iinlining_processed_edges, dst->uid);
+  for (i = 0; i < vec_safe_length (old_args->jump_functions); i++)
+    (*new_args->jump_functions)[i].agg.items
+       = vec_safe_copy ((*old_args->jump_functions)[i].agg.items);
 }
 
 /* Hook that is called by cgraph.c when a node is duplicated.  */
 }
 
 /* Hook that is called by cgraph.c when a node is duplicated.  */
@@ -2041,26 +2507,44 @@ ipa_node_duplication_hook (struct cgraph_node *src, struct cgraph_node *dst,
                           ATTRIBUTE_UNUSED void *data)
 {
   struct ipa_node_params *old_info, *new_info;
                           ATTRIBUTE_UNUSED void *data)
 {
   struct ipa_node_params *old_info, *new_info;
-  int param_count, i;
+  struct ipa_agg_replacement_value *old_av, *new_av;
 
   ipa_check_create_node_params ();
   old_info = IPA_NODE_REF (src);
   new_info = IPA_NODE_REF (dst);
 
   ipa_check_create_node_params ();
   old_info = IPA_NODE_REF (src);
   new_info = IPA_NODE_REF (dst);
-  param_count = ipa_get_param_count (old_info);
 
 
-  ipa_set_param_count (new_info, param_count);
-  new_info->params = (struct ipa_param_descriptor *)
-    duplicate_array (old_info->params,
-                    sizeof (struct ipa_param_descriptor) * param_count);
-  for (i = 0; i < param_count; i++)
-    new_info->params[i].types = VEC_copy (tree, heap,
-                                         old_info->params[i].types);
+  new_info->descriptors = old_info->descriptors.copy ();
+  new_info->lattices = NULL;
   new_info->ipcp_orig_node = old_info->ipcp_orig_node;
   new_info->ipcp_orig_node = old_info->ipcp_orig_node;
-  new_info->count_scale = old_info->count_scale;
 
 
-  new_info->called_with_var_arguments = old_info->called_with_var_arguments;
   new_info->uses_analysis_done = old_info->uses_analysis_done;
   new_info->node_enqueued = old_info->node_enqueued;
   new_info->uses_analysis_done = old_info->uses_analysis_done;
   new_info->node_enqueued = old_info->node_enqueued;
+
+  old_av = ipa_get_agg_replacements_for_node (src);
+  if (!old_av)
+    return;
+
+  new_av = NULL;
+  while (old_av)
+    {
+      struct ipa_agg_replacement_value *v;
+
+      v = ggc_alloc_ipa_agg_replacement_value ();
+      memcpy (v, old_av, sizeof (*v));
+      v->next = new_av;
+      new_av = v;
+      old_av = old_av->next;
+    }
+  ipa_set_node_agg_value_chain (dst, new_av);
+}
+
+
+/* Analyze newly added function into callgraph.  */
+
+static void
+ipa_add_new_function (struct cgraph_node *node, void *data ATTRIBUTE_UNUSED)
+{
+  ipa_analyze_node (node);
 }
 
 /* Register our cgraph hooks if they are not already there.  */
 }
 
 /* Register our cgraph hooks if they are not already there.  */
@@ -2080,6 +2564,8 @@ ipa_register_cgraph_hooks (void)
   if (!node_duplication_hook_holder)
     node_duplication_hook_holder =
       cgraph_add_node_duplication_hook (&ipa_node_duplication_hook, NULL);
   if (!node_duplication_hook_holder)
     node_duplication_hook_holder =
       cgraph_add_node_duplication_hook (&ipa_node_duplication_hook, NULL);
+  function_insertion_hook_holder =
+      cgraph_add_function_insertion_hook (&ipa_add_new_function, NULL);
 }
 
 /* Unregister our cgraph hooks if they are not already there.  */
 }
 
 /* Unregister our cgraph hooks if they are not already there.  */
@@ -2095,14 +2581,8 @@ ipa_unregister_cgraph_hooks (void)
   edge_duplication_hook_holder = NULL;
   cgraph_remove_node_duplication_hook (node_duplication_hook_holder);
   node_duplication_hook_holder = NULL;
   edge_duplication_hook_holder = NULL;
   cgraph_remove_node_duplication_hook (node_duplication_hook_holder);
   node_duplication_hook_holder = NULL;
-}
-
-/* Allocate all necessary data structures necessary for indirect inlining.  */
-
-void
-ipa_create_all_structures_for_iinln (void)
-{
-  iinlining_processed_edges = BITMAP_ALLOC (NULL);
+  cgraph_remove_function_insertion_hook (function_insertion_hook_holder);
+  function_insertion_hook_holder = NULL;
 }
 
 /* Free all ipa_node_params and all ipa_edge_args structures if they are no
 }
 
 /* Free all ipa_node_params and all ipa_edge_args structures if they are no
@@ -2111,10 +2591,13 @@ ipa_create_all_structures_for_iinln (void)
 void
 ipa_free_all_structures_after_ipa_cp (void)
 {
 void
 ipa_free_all_structures_after_ipa_cp (void)
 {
-  if (!flag_indirect_inlining)
+  if (!optimize)
     {
       ipa_free_all_edge_args ();
       ipa_free_all_node_params ();
     {
       ipa_free_all_edge_args ();
       ipa_free_all_node_params ();
+      free_alloc_pool (ipcp_sources_pool);
+      free_alloc_pool (ipcp_values_pool);
+      free_alloc_pool (ipcp_agg_lattice_pool);
       ipa_unregister_cgraph_hooks ();
     }
 }
       ipa_unregister_cgraph_hooks ();
     }
 }
@@ -2125,18 +2608,22 @@ ipa_free_all_structures_after_ipa_cp (void)
 void
 ipa_free_all_structures_after_iinln (void)
 {
 void
 ipa_free_all_structures_after_iinln (void)
 {
-  BITMAP_FREE (iinlining_processed_edges);
-
   ipa_free_all_edge_args ();
   ipa_free_all_node_params ();
   ipa_unregister_cgraph_hooks ();
   ipa_free_all_edge_args ();
   ipa_free_all_node_params ();
   ipa_unregister_cgraph_hooks ();
+  if (ipcp_sources_pool)
+    free_alloc_pool (ipcp_sources_pool);
+  if (ipcp_values_pool)
+    free_alloc_pool (ipcp_values_pool);
+  if (ipcp_agg_lattice_pool)
+    free_alloc_pool (ipcp_agg_lattice_pool);
 }
 
 /* Print ipa_tree_map data structures of all functions in the
    callgraph to F.  */
 
 void
 }
 
 /* Print ipa_tree_map data structures of all functions in the
    callgraph to F.  */
 
 void
-ipa_print_node_params (FILE * f, struct cgraph_node *node)
+ipa_print_node_params (FILE *f, struct cgraph_node *node)
 {
   int i, count;
   tree temp;
 {
   int i, count;
   tree temp;
@@ -2171,23 +2658,23 @@ ipa_print_all_params (FILE * f)
   struct cgraph_node *node;
 
   fprintf (f, "\nFunction parameters:\n");
   struct cgraph_node *node;
 
   fprintf (f, "\nFunction parameters:\n");
-  for (node = cgraph_nodes; node; node = node->next)
+  FOR_EACH_FUNCTION (node)
     ipa_print_node_params (f, node);
 }
 
 /* Return a heap allocated vector containing formal parameters of FNDECL.  */
 
     ipa_print_node_params (f, node);
 }
 
 /* Return a heap allocated vector containing formal parameters of FNDECL.  */
 
-VEC(tree, heap) *
+vec<tree> 
 ipa_get_vector_of_formal_parms (tree fndecl)
 {
 ipa_get_vector_of_formal_parms (tree fndecl)
 {
-  VEC(tree, heap) *args;
+  vec<tree> args;
   int count;
   tree parm;
 
   int count;
   tree parm;
 
-  count = count_formal_params_1 (fndecl);
-  args = VEC_alloc (tree, heap, count);
+  count = count_formal_params (fndecl);
+  args.create (count);
   for (parm = DECL_ARGUMENTS (fndecl); parm; parm = DECL_CHAIN (parm))
   for (parm = DECL_ARGUMENTS (fndecl); parm; parm = DECL_CHAIN (parm))
-    VEC_quick_push (tree, args, parm);
+    args.quick_push (parm);
 
   return args;
 }
 
   return args;
 }
@@ -2195,19 +2682,19 @@ ipa_get_vector_of_formal_parms (tree fndecl)
 /* Return a heap allocated vector containing types of formal parameters of
    function type FNTYPE.  */
 
 /* Return a heap allocated vector containing types of formal parameters of
    function type FNTYPE.  */
 
-static inline VEC(tree, heap) *
+static inline vec<tree> 
 get_vector_of_formal_parm_types (tree fntype)
 {
 get_vector_of_formal_parm_types (tree fntype)
 {
-  VEC(tree, heap) *types;
+  vec<tree> types;
   int count = 0;
   tree t;
 
   for (t = TYPE_ARG_TYPES (fntype); t; t = TREE_CHAIN (t))
     count++;
 
   int count = 0;
   tree t;
 
   for (t = TYPE_ARG_TYPES (fntype); t; t = TREE_CHAIN (t))
     count++;
 
-  types = VEC_alloc (tree, heap, count);
+  types.create (count);
   for (t = TYPE_ARG_TYPES (fntype); t; t = TREE_CHAIN (t))
   for (t = TYPE_ARG_TYPES (fntype); t; t = TREE_CHAIN (t))
-    VEC_quick_push (tree, types, TREE_VALUE (t));
+    types.quick_push (TREE_VALUE (t));
 
   return types;
 }
 
   return types;
 }
@@ -2221,11 +2708,11 @@ void
 ipa_modify_formal_parameters (tree fndecl, ipa_parm_adjustment_vec adjustments,
                              const char *synth_parm_prefix)
 {
 ipa_modify_formal_parameters (tree fndecl, ipa_parm_adjustment_vec adjustments,
                              const char *synth_parm_prefix)
 {
-  VEC(tree, heap) *oparms, *otypes;
+  vec<tree> oparms, otypes;
   tree orig_type, new_type = NULL;
   tree old_arg_types, t, new_arg_types = NULL;
   tree parm, *link = &DECL_ARGUMENTS (fndecl);
   tree orig_type, new_type = NULL;
   tree old_arg_types, t, new_arg_types = NULL;
   tree parm, *link = &DECL_ARGUMENTS (fndecl);
-  int i, len = VEC_length (ipa_parm_adjustment_t, adjustments);
+  int i, len = adjustments.length ();
   tree new_reversed = NULL;
   bool care_for_types, last_parm_void;
 
   tree new_reversed = NULL;
   bool care_for_types, last_parm_void;
 
@@ -2245,14 +2732,14 @@ ipa_modify_formal_parameters (tree fndecl, ipa_parm_adjustment_vec adjustments,
                        == void_type_node);
       otypes = get_vector_of_formal_parm_types (orig_type);
       if (last_parm_void)
                        == void_type_node);
       otypes = get_vector_of_formal_parm_types (orig_type);
       if (last_parm_void)
-       gcc_assert (VEC_length (tree, oparms) + 1 == VEC_length (tree, otypes));
+       gcc_assert (oparms.length () + 1 == otypes.length ());
       else
       else
-       gcc_assert (VEC_length (tree, oparms) == VEC_length (tree, otypes));
+       gcc_assert (oparms.length () == otypes.length ());
     }
   else
     {
       last_parm_void = false;
     }
   else
     {
       last_parm_void = false;
-      otypes = NULL;
+      otypes.create (0);
     }
 
   for (i = 0; i < len; i++)
     }
 
   for (i = 0; i < len; i++)
@@ -2260,15 +2747,14 @@ ipa_modify_formal_parameters (tree fndecl, ipa_parm_adjustment_vec adjustments,
       struct ipa_parm_adjustment *adj;
       gcc_assert (link);
 
       struct ipa_parm_adjustment *adj;
       gcc_assert (link);
 
-      adj = VEC_index (ipa_parm_adjustment_t, adjustments, i);
-      parm = VEC_index (tree, oparms, adj->base_index);
+      adj = &adjustments[i];
+      parm = oparms[adj->base_index];
       adj->base = parm;
 
       if (adj->copy_param)
        {
          if (care_for_types)
       adj->base = parm;
 
       if (adj->copy_param)
        {
          if (care_for_types)
-           new_arg_types = tree_cons (NULL_TREE, VEC_index (tree, otypes,
-                                                            adj->base_index),
+           new_arg_types = tree_cons (NULL_TREE, otypes[adj->base_index],
                                       new_arg_types);
          *link = parm;
          link = &DECL_CHAIN (parm);
                                       new_arg_types);
          *link = parm;
          link = &DECL_CHAIN (parm);
@@ -2297,8 +2783,6 @@ ipa_modify_formal_parameters (tree fndecl, ipa_parm_adjustment_vec adjustments,
          DECL_IGNORED_P (new_parm) = 1;
          layout_decl (new_parm, 0);
 
          DECL_IGNORED_P (new_parm) = 1;
          layout_decl (new_parm, 0);
 
-         add_referenced_var (new_parm);
-         mark_sym_for_renaming (new_parm);
          adj->base = parm;
          adj->reduction = new_parm;
 
          adj->base = parm;
          adj->reduction = new_parm;
 
@@ -2328,8 +2812,8 @@ ipa_modify_formal_parameters (tree fndecl, ipa_parm_adjustment_vec adjustments,
      When we are asked to remove it, we need to build new FUNCTION_TYPE
      instead.  */
   if (TREE_CODE (orig_type) != METHOD_TYPE
      When we are asked to remove it, we need to build new FUNCTION_TYPE
      instead.  */
   if (TREE_CODE (orig_type) != METHOD_TYPE
-       || (VEC_index (ipa_parm_adjustment_t, adjustments, 0)->copy_param
-        && VEC_index (ipa_parm_adjustment_t, adjustments, 0)->base_index == 0))
+       || (adjustments[0].copy_param
+         && adjustments[0].base_index == 0))
     {
       new_type = build_distinct_type_copy (orig_type);
       TYPE_ARG_TYPES (new_type) = new_reversed;
     {
       new_type = build_distinct_type_copy (orig_type);
       TYPE_ARG_TYPES (new_type) = new_reversed;
@@ -2367,9 +2851,8 @@ ipa_modify_formal_parameters (tree fndecl, ipa_parm_adjustment_vec adjustments,
 
   TREE_TYPE (fndecl) = new_type;
   DECL_VIRTUAL_P (fndecl) = 0;
 
   TREE_TYPE (fndecl) = new_type;
   DECL_VIRTUAL_P (fndecl) = 0;
-  if (otypes)
-    VEC_free (tree, heap, otypes);
-  VEC_free (tree, heap, oparms);
+  otypes.release ();
+  oparms.release ();
 }
 
 /* Modify actual arguments of a function call CS as indicated in ADJUSTMENTS.
 }
 
 /* Modify actual arguments of a function call CS as indicated in ADJUSTMENTS.
@@ -2380,32 +2863,36 @@ void
 ipa_modify_call_arguments (struct cgraph_edge *cs, gimple stmt,
                           ipa_parm_adjustment_vec adjustments)
 {
 ipa_modify_call_arguments (struct cgraph_edge *cs, gimple stmt,
                           ipa_parm_adjustment_vec adjustments)
 {
-  VEC(tree, heap) *vargs;
+  vec<tree> vargs;
+  vec<tree, va_gc> **debug_args = NULL;
   gimple new_stmt;
   gimple_stmt_iterator gsi;
   tree callee_decl;
   int i, len;
 
   gimple new_stmt;
   gimple_stmt_iterator gsi;
   tree callee_decl;
   int i, len;
 
-  len = VEC_length (ipa_parm_adjustment_t, adjustments);
-  vargs = VEC_alloc (tree, heap, len);
+  len = adjustments.length ();
+  vargs.create (len);
+  callee_decl = !cs ? gimple_call_fndecl (stmt) : cs->callee->symbol.decl;
 
   gsi = gsi_for_stmt (stmt);
   for (i = 0; i < len; i++)
     {
       struct ipa_parm_adjustment *adj;
 
 
   gsi = gsi_for_stmt (stmt);
   for (i = 0; i < len; i++)
     {
       struct ipa_parm_adjustment *adj;
 
-      adj = VEC_index (ipa_parm_adjustment_t, adjustments, i);
+      adj = &adjustments[i];
 
       if (adj->copy_param)
        {
          tree arg = gimple_call_arg (stmt, adj->base_index);
 
 
       if (adj->copy_param)
        {
          tree arg = gimple_call_arg (stmt, adj->base_index);
 
-         VEC_quick_push (tree, vargs, arg);
+         vargs.quick_push (arg);
        }
       else if (!adj->remove_param)
        {
          tree expr, base, off;
          location_t loc;
        }
       else if (!adj->remove_param)
        {
          tree expr, base, off;
          location_t loc;
+         unsigned int deref_align;
+         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:
 
          /* We create a new parameter out of the value of the old one, we can
             do the following kind of transformations:
@@ -2428,7 +2915,8 @@ ipa_modify_call_arguments (struct cgraph_edge *cs, gimple stmt,
 
          gcc_checking_assert (adj->offset % BITS_PER_UNIT == 0);
          base = gimple_call_arg (stmt, adj->base_index);
 
          gcc_checking_assert (adj->offset % BITS_PER_UNIT == 0);
          base = gimple_call_arg (stmt, adj->base_index);
-         loc = EXPR_LOCATION (base);
+         loc = DECL_P (base) ? DECL_SOURCE_LOCATION (base)
+                             : EXPR_LOCATION (base);
 
          if (TREE_CODE (base) != ADDR_EXPR
              && POINTER_TYPE_P (TREE_TYPE (base)))
 
          if (TREE_CODE (base) != ADDR_EXPR
              && POINTER_TYPE_P (TREE_TYPE (base)))
@@ -2438,9 +2926,15 @@ ipa_modify_call_arguments (struct cgraph_edge *cs, gimple stmt,
            {
              HOST_WIDE_INT base_offset;
              tree prev_base;
            {
              HOST_WIDE_INT base_offset;
              tree prev_base;
+             bool addrof;
 
              if (TREE_CODE (base) == ADDR_EXPR)
 
              if (TREE_CODE (base) == ADDR_EXPR)
-               base = TREE_OPERAND (base, 0);
+               {
+                 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.  */
              prev_base = base;
              base = get_addr_base_and_unit_offset (base, &base_offset);
              /* Aggregate arguments can have non-invariant addresses.  */
@@ -2452,11 +2946,16 @@ ipa_modify_call_arguments (struct cgraph_edge *cs, gimple stmt,
                }
              else if (TREE_CODE (base) == MEM_REF)
                {
                }
              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 = 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, 0);
+                                        off);
                  base = TREE_OPERAND (base, 0);
                }
              else
                  base = TREE_OPERAND (base, 0);
                }
              else
@@ -2468,15 +2967,79 @@ ipa_modify_call_arguments (struct cgraph_edge *cs, gimple stmt,
                }
            }
 
                }
            }
 
-         expr = fold_build2_loc (loc, MEM_REF, adj->type, base, off);
-         if (adj->by_ref)
-           expr = build_fold_addr_expr (expr);
+         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 += (tree_to_double_int (off)
+                          .sext (TYPE_PRECISION (TREE_TYPE (off))).low
+                          * BITS_PER_UNIT);
+             misalign = misalign & (align - 1);
+             if (misalign != 0)
+               align = (misalign & -misalign);
+             if (align < TYPE_ALIGN (type))
+               type = build_aligned_type (type, align);
+             expr = fold_build2_loc (loc, MEM_REF, type, base, off);
+           }
+         else
+           {
+             expr = fold_build2_loc (loc, MEM_REF, adj->type, base, off);
+             expr = build_fold_addr_expr (expr);
+           }
 
          expr = force_gimple_operand_gsi (&gsi, expr,
                                           adj->by_ref
                                           || is_gimple_reg_type (adj->type),
                                           NULL, true, GSI_SAME_STMT);
 
          expr = force_gimple_operand_gsi (&gsi, expr,
                                           adj->by_ref
                                           || is_gimple_reg_type (adj->type),
                                           NULL, true, GSI_SAME_STMT);
-         VEC_quick_push (tree, vargs, expr);
+         vargs.quick_push (expr);
+       }
+      if (!adj->copy_param && 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);
+             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);
        }
     }
 
        }
     }
 
@@ -2486,17 +3049,16 @@ ipa_modify_call_arguments (struct cgraph_edge *cs, gimple stmt,
       print_gimple_stmt (dump_file, gsi_stmt (gsi), 0, 0);
     }
 
       print_gimple_stmt (dump_file, gsi_stmt (gsi), 0, 0);
     }
 
-  callee_decl = !cs ? gimple_call_fndecl (stmt) : cs->callee->decl;
   new_stmt = gimple_build_call_vec (callee_decl, vargs);
   new_stmt = gimple_build_call_vec (callee_decl, vargs);
-  VEC_free (tree, heap, 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));
   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_copy_flags (new_stmt, stmt);
   gimple_call_set_chain (new_stmt, gimple_call_chain (stmt));
   gimple_call_set_chain (new_stmt, gimple_call_chain (stmt));
+  gimple_call_copy_flags (new_stmt, stmt);
 
   if (dump_file && (dump_flags & TDF_DETAILS))
     {
 
   if (dump_file && (dump_flags & TDF_DETAILS))
     {
@@ -2517,13 +3079,13 @@ static bool
 index_in_adjustments_multiple_times_p (int base_index,
                                       ipa_parm_adjustment_vec adjustments)
 {
 index_in_adjustments_multiple_times_p (int base_index,
                                       ipa_parm_adjustment_vec adjustments)
 {
-  int i, len = VEC_length (ipa_parm_adjustment_t, adjustments);
+  int i, len = adjustments.length ();
   bool one = false;
 
   for (i = 0; i < len; i++)
     {
       struct ipa_parm_adjustment *adj;
   bool one = false;
 
   for (i = 0; i < len; i++)
     {
       struct ipa_parm_adjustment *adj;
-      adj = VEC_index (ipa_parm_adjustment_t, adjustments, i);
+      adj = &adjustments[i];
 
       if (adj->base_index == base_index)
        {
 
       if (adj->base_index == base_index)
        {
@@ -2545,71 +3107,67 @@ ipa_parm_adjustment_vec
 ipa_combine_adjustments (ipa_parm_adjustment_vec inner,
                         ipa_parm_adjustment_vec outer)
 {
 ipa_combine_adjustments (ipa_parm_adjustment_vec inner,
                         ipa_parm_adjustment_vec outer)
 {
-  int i, outlen = VEC_length (ipa_parm_adjustment_t, outer);
-  int inlen = VEC_length (ipa_parm_adjustment_t, inner);
+  int i, outlen = outer.length ();
+  int inlen = inner.length ();
   int removals = 0;
   ipa_parm_adjustment_vec adjustments, tmp;
 
   int removals = 0;
   ipa_parm_adjustment_vec adjustments, tmp;
 
-  tmp = VEC_alloc (ipa_parm_adjustment_t, heap, inlen);
+  tmp.create (inlen);
   for (i = 0; i < inlen; i++)
     {
       struct ipa_parm_adjustment *n;
   for (i = 0; i < inlen; i++)
     {
       struct ipa_parm_adjustment *n;
-      n = VEC_index (ipa_parm_adjustment_t, inner, i);
+      n = &inner[i];
 
       if (n->remove_param)
        removals++;
       else
 
       if (n->remove_param)
        removals++;
       else
-       VEC_quick_push (ipa_parm_adjustment_t, tmp, n);
+       tmp.quick_push (*n);
     }
 
     }
 
-  adjustments = VEC_alloc (ipa_parm_adjustment_t, heap, outlen + removals);
+  adjustments.create (outlen + removals);
   for (i = 0; i < outlen; i++)
     {
   for (i = 0; i < outlen; i++)
     {
-      struct ipa_parm_adjustment *r;
-      struct ipa_parm_adjustment *out = VEC_index (ipa_parm_adjustment_t,
-                                                  outer, i);
-      struct ipa_parm_adjustment *in = VEC_index (ipa_parm_adjustment_t, tmp,
-                                                 out->base_index);
+      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->remove_param);
       if (out->remove_param)
        {
          if (!index_in_adjustments_multiple_times_p (in->base_index, tmp))
            {
       gcc_assert (!in->remove_param);
       if (out->remove_param)
        {
          if (!index_in_adjustments_multiple_times_p (in->base_index, tmp))
            {
-             r = VEC_quick_push (ipa_parm_adjustment_t, adjustments, NULL);
-             memset (r, 0, sizeof (*r));
-             r->remove_param = true;
+             r.remove_param = true;
+             adjustments.quick_push (r);
            }
          continue;
        }
 
            }
          continue;
        }
 
-      r = VEC_quick_push (ipa_parm_adjustment_t, adjustments, NULL);
-      memset (r, 0, sizeof (*r));
-      r->base_index = in->base_index;
-      r->type = out->type;
+      r.base_index = in->base_index;
+      r.type = out->type;
 
       /* FIXME:  Create nonlocal value too.  */
 
       if (in->copy_param && out->copy_param)
 
       /* FIXME:  Create nonlocal value too.  */
 
       if (in->copy_param && out->copy_param)
-       r->copy_param = true;
+       r.copy_param = true;
       else if (in->copy_param)
       else if (in->copy_param)
-       r->offset = out->offset;
+       r.offset = out->offset;
       else if (out->copy_param)
       else if (out->copy_param)
-       r->offset = in->offset;
+       r.offset = in->offset;
       else
       else
-       r->offset = in->offset + out->offset;
+       r.offset = in->offset + out->offset;
+      adjustments.quick_push (r);
     }
 
   for (i = 0; i < inlen; i++)
     {
     }
 
   for (i = 0; i < inlen; i++)
     {
-      struct ipa_parm_adjustment *n = VEC_index (ipa_parm_adjustment_t,
-                                                inner, i);
+      struct ipa_parm_adjustment *n = &inner[i];
 
       if (n->remove_param)
 
       if (n->remove_param)
-       VEC_quick_push (ipa_parm_adjustment_t, adjustments, n);
+       adjustments.quick_push (*n);
     }
 
     }
 
-  VEC_free (ipa_parm_adjustment_t, heap, tmp);
+  tmp.release ();
   return adjustments;
 }
 
   return adjustments;
 }
 
@@ -2620,15 +3178,15 @@ void
 ipa_dump_param_adjustments (FILE *file, ipa_parm_adjustment_vec adjustments,
                            tree fndecl)
 {
 ipa_dump_param_adjustments (FILE *file, ipa_parm_adjustment_vec adjustments,
                            tree fndecl)
 {
-  int i, len = VEC_length (ipa_parm_adjustment_t, adjustments);
+  int i, len = adjustments.length ();
   bool first = true;
   bool first = true;
-  VEC(tree, heap) *parms = ipa_get_vector_of_formal_parms (fndecl);
+  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;
 
   fprintf (file, "IPA param adjustments: ");
   for (i = 0; i < len; i++)
     {
       struct ipa_parm_adjustment *adj;
-      adj = VEC_index (ipa_parm_adjustment_t, adjustments, i);
+      adj = &adjustments[i];
 
       if (!first)
        fprintf (file, "                 ");
 
       if (!first)
        fprintf (file, "                 ");
@@ -2636,7 +3194,7 @@ ipa_dump_param_adjustments (FILE *file, ipa_parm_adjustment_vec adjustments,
        first = false;
 
       fprintf (file, "%i. base_index: %i - ", i, adj->base_index);
        first = false;
 
       fprintf (file, "%i. base_index: %i - ", i, adj->base_index);
-      print_generic_expr (file, VEC_index (tree, parms, adj->base_index), 0);
+      print_generic_expr (file, parms[adj->base_index], 0);
       if (adj->base)
        {
          fprintf (file, ", base: ");
       if (adj->base)
        {
          fprintf (file, ", base: ");
@@ -2664,7 +3222,24 @@ ipa_dump_param_adjustments (FILE *file, ipa_parm_adjustment_vec adjustments,
       print_node_brief (file, ", type: ", adj->type, 0);
       fprintf (file, "\n");
     }
       print_node_brief (file, ", type: ", adj->type, 0);
       fprintf (file, "\n");
     }
-  VEC_free (tree, heap, parms);
+  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.  */
 }
 
 /* Stream out jump function JUMP_FUNC to OB.  */
@@ -2673,38 +3248,57 @@ static void
 ipa_write_jump_function (struct output_block *ob,
                         struct ipa_jump_func *jump_func)
 {
 ipa_write_jump_function (struct output_block *ob,
                         struct ipa_jump_func *jump_func)
 {
-  lto_output_uleb128_stream (ob->main_stream,
-                            jump_func->type);
+  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_KNOWN_TYPE:
   switch (jump_func->type)
     {
     case IPA_JF_UNKNOWN:
       break;
     case IPA_JF_KNOWN_TYPE:
-      lto_output_tree (ob, jump_func->value.base_binfo, true);
+      streamer_write_uhwi (ob, jump_func->value.known_type.offset);
+      stream_write_tree (ob, jump_func->value.known_type.base_type, true);
+      stream_write_tree (ob, jump_func->value.known_type.component_type, true);
       break;
     case IPA_JF_CONST:
       break;
     case IPA_JF_CONST:
-      lto_output_tree (ob, jump_func->value.constant, true);
+      gcc_assert (
+         EXPR_LOCATION (jump_func->value.constant) == UNKNOWN_LOCATION);
+      stream_write_tree (ob, jump_func->value.constant, true);
       break;
     case IPA_JF_PASS_THROUGH:
       break;
     case IPA_JF_PASS_THROUGH:
-      lto_output_tree (ob, jump_func->value.pass_through.operand, true);
-      lto_output_uleb128_stream (ob->main_stream,
-                                jump_func->value.pass_through.formal_id);
-      lto_output_uleb128_stream (ob->main_stream,
-                                jump_func->value.pass_through.operation);
+      stream_write_tree (ob, jump_func->value.pass_through.operand, true);
+      streamer_write_uhwi (ob, jump_func->value.pass_through.formal_id);
+      streamer_write_uhwi (ob, jump_func->value.pass_through.operation);
+      bp = bitpack_create (ob->main_stream);
+      bp_pack_value (&bp, jump_func->value.pass_through.agg_preserved, 1);
+      streamer_write_bitpack (&bp);
       break;
     case IPA_JF_ANCESTOR:
       break;
     case IPA_JF_ANCESTOR:
-      lto_output_uleb128_stream (ob->main_stream,
-                                jump_func->value.ancestor.offset);
-      lto_output_tree (ob, jump_func->value.ancestor.type, true);
-      lto_output_uleb128_stream (ob->main_stream,
-                                jump_func->value.ancestor.formal_id);
-      break;
-    case IPA_JF_CONST_MEMBER_PTR:
-      lto_output_tree (ob, jump_func->value.member_cst.pfn, true);
-      lto_output_tree (ob, jump_func->value.member_cst.delta, false);
+      streamer_write_uhwi (ob, jump_func->value.ancestor.offset);
+      stream_write_tree (ob, jump_func->value.ancestor.type, true);
+      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;
     }
       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);
+    }
 }
 
 /* Read in jump function JUMP_FUNC from IB.  */
 }
 
 /* Read in jump function JUMP_FUNC from IB.  */
@@ -2714,33 +3308,54 @@ ipa_read_jump_function (struct lto_input_block *ib,
                        struct ipa_jump_func *jump_func,
                        struct data_in *data_in)
 {
                        struct ipa_jump_func *jump_func,
                        struct data_in *data_in)
 {
-  jump_func->type = (enum jump_func_type) lto_input_uleb128 (ib);
+  struct bitpack_d bp;
+  int i, count;
 
 
+  jump_func->type = (enum jump_func_type) streamer_read_uhwi (ib);
   switch (jump_func->type)
     {
     case IPA_JF_UNKNOWN:
       break;
     case IPA_JF_KNOWN_TYPE:
   switch (jump_func->type)
     {
     case IPA_JF_UNKNOWN:
       break;
     case IPA_JF_KNOWN_TYPE:
-      jump_func->value.base_binfo = lto_input_tree (ib, data_in);
+      jump_func->value.known_type.offset = streamer_read_uhwi (ib);
+      jump_func->value.known_type.base_type = stream_read_tree (ib, data_in);
+      jump_func->value.known_type.component_type = stream_read_tree (ib,
+                                                                    data_in);
       break;
     case IPA_JF_CONST:
       break;
     case IPA_JF_CONST:
-      jump_func->value.constant = lto_input_tree (ib, data_in);
+      jump_func->value.constant = stream_read_tree (ib, data_in);
       break;
     case IPA_JF_PASS_THROUGH:
       break;
     case IPA_JF_PASS_THROUGH:
-      jump_func->value.pass_through.operand = lto_input_tree (ib, data_in);
-      jump_func->value.pass_through.formal_id = lto_input_uleb128 (ib);
-      jump_func->value.pass_through.operation = (enum tree_code) lto_input_uleb128 (ib);
+      jump_func->value.pass_through.operand = stream_read_tree (ib, data_in);
+      jump_func->value.pass_through.formal_id = streamer_read_uhwi (ib);
+      jump_func->value.pass_through.operation
+       = (enum tree_code) streamer_read_uhwi (ib);
+      bp = streamer_read_bitpack (ib);
+      jump_func->value.pass_through.agg_preserved = bp_unpack_value (&bp, 1);
       break;
     case IPA_JF_ANCESTOR:
       break;
     case IPA_JF_ANCESTOR:
-      jump_func->value.ancestor.offset = lto_input_uleb128 (ib);
-      jump_func->value.ancestor.type = lto_input_tree (ib, data_in);
-      jump_func->value.ancestor.formal_id = lto_input_uleb128 (ib);
-      break;
-    case IPA_JF_CONST_MEMBER_PTR:
-      jump_func->value.member_cst.pfn = lto_input_tree (ib, data_in);
-      jump_func->value.member_cst.delta = lto_input_tree (ib, data_in);
+      jump_func->value.ancestor.offset = streamer_read_uhwi (ib);
+      jump_func->value.ancestor.type = stream_read_tree (ib, data_in);
+      jump_func->value.ancestor.formal_id = streamer_read_uhwi (ib);
+      bp = streamer_read_bitpack (ib);
+      jump_func->value.ancestor.agg_preserved = bp_unpack_value (&bp, 1);
       break;
     }
       break;
     }
+
+  count = streamer_read_uhwi (ib);
+  vec_alloc (jump_func->agg.items, count);
+  if (count)
+    {
+      bp = streamer_read_bitpack (ib);
+      jump_func->agg.by_ref = bp_unpack_value (&bp, 1);
+    }
+  for (i = 0; i < count; i++)
+    {
+      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);
+    }
 }
 
 /* Stream out parts of cgraph_indirect_call_info corresponding to CS that are
 }
 
 /* Stream out parts of cgraph_indirect_call_info corresponding to CS that are
@@ -2753,16 +3368,18 @@ ipa_write_indirect_edge_info (struct output_block *ob,
   struct cgraph_indirect_call_info *ii = cs->indirect_info;
   struct bitpack_d bp;
 
   struct cgraph_indirect_call_info *ii = cs->indirect_info;
   struct bitpack_d bp;
 
-  lto_output_sleb128_stream (ob->main_stream, ii->param_index);
-  lto_output_sleb128_stream (ob->main_stream, ii->anc_offset);
+  streamer_write_hwi (ob, ii->param_index);
+  streamer_write_hwi (ob, ii->offset);
   bp = bitpack_create (ob->main_stream);
   bp_pack_value (&bp, ii->polymorphic, 1);
   bp = bitpack_create (ob->main_stream);
   bp_pack_value (&bp, ii->polymorphic, 1);
-  lto_output_bitpack (&bp);
+  bp_pack_value (&bp, ii->agg_contents, 1);
+  bp_pack_value (&bp, ii->by_ref, 1);
+  streamer_write_bitpack (&bp);
 
   if (ii->polymorphic)
     {
 
   if (ii->polymorphic)
     {
-      lto_output_sleb128_stream (ob->main_stream, ii->otr_token);
-      lto_output_tree (ob, ii->otr_type, true);
+      streamer_write_hwi (ob, ii->otr_token);
+      stream_write_tree (ob, ii->otr_type, true);
     }
 }
 
     }
 }
 
@@ -2777,14 +3394,16 @@ ipa_read_indirect_edge_info (struct lto_input_block *ib,
   struct cgraph_indirect_call_info *ii = cs->indirect_info;
   struct bitpack_d bp;
 
   struct cgraph_indirect_call_info *ii = cs->indirect_info;
   struct bitpack_d bp;
 
-  ii->param_index = (int) lto_input_sleb128 (ib);
-  ii->anc_offset = (HOST_WIDE_INT) lto_input_sleb128 (ib);
-  bp = lto_input_bitpack (ib);
+  ii->param_index = (int) streamer_read_hwi (ib);
+  ii->offset = (HOST_WIDE_INT) streamer_read_hwi (ib);
+  bp = streamer_read_bitpack (ib);
   ii->polymorphic = bp_unpack_value (&bp, 1);
   ii->polymorphic = bp_unpack_value (&bp, 1);
+  ii->agg_contents = bp_unpack_value (&bp, 1);
+  ii->by_ref = bp_unpack_value (&bp, 1);
   if (ii->polymorphic)
     {
   if (ii->polymorphic)
     {
-      ii->otr_token = (HOST_WIDE_INT) lto_input_sleb128 (ib);
-      ii->otr_type = lto_input_tree (ib, data_in);
+      ii->otr_token = (HOST_WIDE_INT) streamer_read_hwi (ib);
+      ii->otr_type = stream_read_tree (ib, data_in);
     }
 }
 
     }
 }
 
@@ -2794,36 +3413,41 @@ static void
 ipa_write_node_info (struct output_block *ob, struct cgraph_node *node)
 {
   int node_ref;
 ipa_write_node_info (struct output_block *ob, struct cgraph_node *node)
 {
   int node_ref;
-  lto_cgraph_encoder_t encoder;
+  lto_symtab_encoder_t encoder;
   struct ipa_node_params *info = IPA_NODE_REF (node);
   int j;
   struct cgraph_edge *e;
   struct bitpack_d bp;
 
   struct ipa_node_params *info = IPA_NODE_REF (node);
   int j;
   struct cgraph_edge *e;
   struct bitpack_d bp;
 
-  encoder = ob->decl_state->cgraph_node_encoder;
-  node_ref = lto_cgraph_encoder_encode (encoder, node);
-  lto_output_uleb128_stream (ob->main_stream, node_ref);
+  encoder = ob->decl_state->symtab_node_encoder;
+  node_ref = lto_symtab_encoder_encode (encoder, (symtab_node) node);
+  streamer_write_uhwi (ob, node_ref);
 
   bp = bitpack_create (ob->main_stream);
 
   bp = bitpack_create (ob->main_stream);
-  bp_pack_value (&bp, info->called_with_var_arguments, 1);
   gcc_assert (info->uses_analysis_done
              || ipa_get_param_count (info) == 0);
   gcc_assert (!info->node_enqueued);
   gcc_assert (!info->ipcp_orig_node);
   for (j = 0; j < ipa_get_param_count (info); j++)
   gcc_assert (info->uses_analysis_done
              || ipa_get_param_count (info) == 0);
   gcc_assert (!info->node_enqueued);
   gcc_assert (!info->ipcp_orig_node);
   for (j = 0; j < ipa_get_param_count (info); j++)
-    bp_pack_value (&bp, info->params[j].used, 1);
-  lto_output_bitpack (&bp);
+    bp_pack_value (&bp, ipa_is_param_used (info, j), 1);
+  streamer_write_bitpack (&bp);
   for (e = node->callees; e; e = e->next_callee)
     {
       struct ipa_edge_args *args = IPA_EDGE_REF (e);
 
   for (e = node->callees; e; e = e->next_callee)
     {
       struct ipa_edge_args *args = IPA_EDGE_REF (e);
 
-      lto_output_uleb128_stream (ob->main_stream,
-                                ipa_get_cs_argument_count (args));
+      streamer_write_uhwi (ob, ipa_get_cs_argument_count (args));
       for (j = 0; j < ipa_get_cs_argument_count (args); j++)
        ipa_write_jump_function (ob, ipa_get_ith_jump_func (args, j));
     }
   for (e = node->indirect_calls; e; e = e->next_callee)
       for (j = 0; j < ipa_get_cs_argument_count (args); j++)
        ipa_write_jump_function (ob, ipa_get_ith_jump_func (args, j));
     }
   for (e = node->indirect_calls; e; e = e->next_callee)
-    ipa_write_indirect_edge_info (ob, e);
+    {
+      struct ipa_edge_args *args = IPA_EDGE_REF (e);
+
+      streamer_write_uhwi (ob, ipa_get_cs_argument_count (args));
+      for (j = 0; j < ipa_get_cs_argument_count (args); j++)
+       ipa_write_jump_function (ob, ipa_get_ith_jump_func (args, j));
+      ipa_write_indirect_edge_info (ob, e);
+    }
 }
 
 /* Stream in NODE info from IB.  */
 }
 
 /* Stream in NODE info from IB.  */
@@ -2839,60 +3463,79 @@ ipa_read_node_info (struct lto_input_block *ib, struct cgraph_node *node,
 
   ipa_initialize_node_params (node);
 
 
   ipa_initialize_node_params (node);
 
-  bp = lto_input_bitpack (ib);
-  info->called_with_var_arguments = bp_unpack_value (&bp, 1);
+  bp = streamer_read_bitpack (ib);
   if (ipa_get_param_count (info) != 0)
     info->uses_analysis_done = true;
   info->node_enqueued = false;
   for (k = 0; k < ipa_get_param_count (info); k++)
   if (ipa_get_param_count (info) != 0)
     info->uses_analysis_done = true;
   info->node_enqueued = false;
   for (k = 0; k < ipa_get_param_count (info); k++)
-    info->params[k].used = bp_unpack_value (&bp, 1);
+    ipa_set_param_used (info, k, bp_unpack_value (&bp, 1));
   for (e = node->callees; e; e = e->next_callee)
     {
       struct ipa_edge_args *args = IPA_EDGE_REF (e);
   for (e = node->callees; e; e = e->next_callee)
     {
       struct ipa_edge_args *args = IPA_EDGE_REF (e);
-      int count = lto_input_uleb128 (ib);
+      int count = streamer_read_uhwi (ib);
 
 
-      ipa_set_cs_argument_count (args, count);
       if (!count)
        continue;
       if (!count)
        continue;
+      vec_safe_grow_cleared (args->jump_functions, count);
 
 
-      args->jump_functions = ggc_alloc_cleared_vec_ipa_jump_func
-       (ipa_get_cs_argument_count (args));
       for (k = 0; k < ipa_get_cs_argument_count (args); k++)
        ipa_read_jump_function (ib, ipa_get_ith_jump_func (args, k), data_in);
     }
   for (e = node->indirect_calls; e; e = e->next_callee)
       for (k = 0; k < ipa_get_cs_argument_count (args); k++)
        ipa_read_jump_function (ib, ipa_get_ith_jump_func (args, k), data_in);
     }
   for (e = node->indirect_calls; e; e = e->next_callee)
-    ipa_read_indirect_edge_info (ib, data_in, e);
+    {
+      struct ipa_edge_args *args = IPA_EDGE_REF (e);
+      int count = streamer_read_uhwi (ib);
+
+      if (count)
+       {
+         vec_safe_grow_cleared (args->jump_functions, count);
+          for (k = 0; k < ipa_get_cs_argument_count (args); k++)
+           ipa_read_jump_function (ib, ipa_get_ith_jump_func (args, k),
+                                   data_in);
+       }
+      ipa_read_indirect_edge_info (ib, data_in, e);
+    }
 }
 
 /* Write jump functions for nodes in SET.  */
 
 void
 }
 
 /* Write jump functions for nodes in SET.  */
 
 void
-ipa_prop_write_jump_functions (cgraph_node_set set)
+ipa_prop_write_jump_functions (void)
 {
   struct cgraph_node *node;
 {
   struct cgraph_node *node;
-  struct output_block *ob = create_output_block (LTO_section_jump_functions);
+  struct output_block *ob;
   unsigned int count = 0;
   unsigned int count = 0;
-  cgraph_node_set_iterator csi;
+  lto_symtab_encoder_iterator lsei;
+  lto_symtab_encoder_t encoder;
 
 
-  ob->cgraph_node = NULL;
 
 
-  for (csi = csi_start (set); !csi_end_p (csi); csi_next (&csi))
+  if (!ipa_node_params_vector.exists ())
+    return;
+
+  ob = create_output_block (LTO_section_jump_functions);
+  encoder = ob->decl_state->symtab_node_encoder;
+  ob->cgraph_node = NULL;
+  for (lsei = lsei_start_function_in_partition (encoder); !lsei_end_p (lsei);
+       lsei_next_function_in_partition (&lsei))
     {
     {
-      node = csi_node (csi);
-      if (node->analyzed && IPA_NODE_REF (node) != NULL)
+      node = lsei_cgraph_node (lsei);
+      if (cgraph_function_with_gimple_body_p (node)
+         && IPA_NODE_REF (node) != NULL)
        count++;
     }
 
        count++;
     }
 
-  lto_output_uleb128_stream (ob->main_stream, count);
+  streamer_write_uhwi (ob, count);
 
   /* Process all of the functions.  */
 
   /* Process all of the functions.  */
-  for (csi = csi_start (set); !csi_end_p (csi); csi_next (&csi))
+  for (lsei = lsei_start_function_in_partition (encoder); !lsei_end_p (lsei);
+       lsei_next_function_in_partition (&lsei))
     {
     {
-      node = csi_node (csi);
-      if (node->analyzed && IPA_NODE_REF (node) != NULL)
+      node = lsei_cgraph_node (lsei);
+      if (cgraph_function_with_gimple_body_p (node)
+         && IPA_NODE_REF (node) != NULL)
         ipa_write_node_info (ob, node);
     }
         ipa_write_node_info (ob, node);
     }
-  lto_output_1_stream (ob->main_stream, 0);
+  streamer_write_char_stream (ob->main_stream, 0);
   produce_asm (ob, NULL);
   destroy_output_block (ob);
 }
   produce_asm (ob, NULL);
   destroy_output_block (ob);
 }
@@ -2905,9 +3548,9 @@ ipa_prop_read_section (struct lto_file_decl_data *file_data, const char *data,
 {
   const struct lto_function_header *header =
     (const struct lto_function_header *) data;
 {
   const struct lto_function_header *header =
     (const struct lto_function_header *) data;
-  const int32_t cfg_offset = sizeof (struct lto_function_header);
-  const int32_t main_offset = cfg_offset + header->cfg_size;
-  const int32_t string_offset = main_offset + header->main_size;
+  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;
   struct lto_input_block ib_main;
   unsigned int i;
   struct data_in *data_in;
   struct lto_input_block ib_main;
   unsigned int i;
@@ -2918,18 +3561,18 @@ ipa_prop_read_section (struct lto_file_decl_data *file_data, const char *data,
 
   data_in =
     lto_data_in_create (file_data, (const char *) data + string_offset,
 
   data_in =
     lto_data_in_create (file_data, (const char *) data + string_offset,
-                       header->string_size, NULL);
-  count = lto_input_uleb128 (&ib_main);
+                       header->string_size, vNULL);
+  count = streamer_read_uhwi (&ib_main);
 
   for (i = 0; i < count; i++)
     {
       unsigned int index;
       struct cgraph_node *node;
 
   for (i = 0; i < count; i++)
     {
       unsigned int index;
       struct cgraph_node *node;
-      lto_cgraph_encoder_t encoder;
+      lto_symtab_encoder_t encoder;
 
 
-      index = lto_input_uleb128 (&ib_main);
-      encoder = file_data->cgraph_node_encoder;
-      node = lto_cgraph_encoder_deref (encoder, index);
+      index = streamer_read_uhwi (&ib_main);
+      encoder = file_data->symtab_node_encoder;
+      node = cgraph (lto_symtab_encoder_deref (encoder, index));
       gcc_assert (node->analyzed);
       ipa_read_node_info (&ib_main, node, data_in);
     }
       gcc_assert (node->analyzed);
       ipa_read_node_info (&ib_main, node, data_in);
     }
@@ -2969,21 +3612,333 @@ void
 ipa_update_after_lto_read (void)
 {
   struct cgraph_node *node;
 ipa_update_after_lto_read (void)
 {
   struct cgraph_node *node;
-  struct cgraph_edge *cs;
 
   ipa_check_create_node_params ();
   ipa_check_create_edge_args ();
 
 
   ipa_check_create_node_params ();
   ipa_check_create_edge_args ();
 
-  for (node = cgraph_nodes; node; node = node->next)
+  FOR_EACH_DEFINED_FUNCTION (node)
     if (node->analyzed)
       ipa_initialize_node_params (node);
     if (node->analyzed)
       ipa_initialize_node_params (node);
+}
 
 
-  for (node = cgraph_nodes; node; node = node->next)
-    if (node->analyzed)
-      for (cs = node->callees; cs; cs = cs->next_callee)
-       {
-         if (ipa_get_cs_argument_count (IPA_EDGE_REF (cs))
-             != ipa_get_param_count (IPA_NODE_REF (cs->callee)))
-           ipa_set_called_with_variable_arg (IPA_NODE_REF (cs->callee));
-       }
+void
+write_agg_replacement_chain (struct output_block *ob, struct cgraph_node *node)
+{
+  int node_ref;
+  unsigned int count = 0;
+  lto_symtab_encoder_t encoder;
+  struct ipa_agg_replacement_value *aggvals, *av;
+
+  aggvals = ipa_get_agg_replacements_for_node (node);
+  encoder = ob->decl_state->symtab_node_encoder;
+  node_ref = lto_symtab_encoder_encode (encoder, (symtab_node) node);
+  streamer_write_uhwi (ob, node_ref);
+
+  for (av = aggvals; av; av = av->next)
+    count++;
+  streamer_write_uhwi (ob, count);
+
+  for (av = aggvals; av; av = av->next)
+    {
+      streamer_write_uhwi (ob, av->offset);
+      streamer_write_uhwi (ob, av->index);
+      stream_write_tree (ob, av->value, true);
+    }
+}
+
+/* Stream in the aggregate value replacement chain for NODE from IB.  */
+
+static void
+read_agg_replacement_chain (struct lto_input_block *ib,
+                           struct cgraph_node *node,
+                           struct data_in *data_in)
+{
+  struct ipa_agg_replacement_value *aggvals = NULL;
+  unsigned int count, i;
+
+  count = streamer_read_uhwi (ib);
+  for (i = 0; i <count; i++)
+    {
+      struct ipa_agg_replacement_value *av;
+
+      av = ggc_alloc_ipa_agg_replacement_value ();
+      av->offset = streamer_read_uhwi (ib);
+      av->index = streamer_read_uhwi (ib);
+      av->value = stream_read_tree (ib, data_in);
+      av->next = aggvals;
+      aggvals = av;
+    }
+  ipa_set_node_agg_value_chain (node, aggvals);
+}
+
+/* Write all aggregate replacement for nodes in set.  */
+
+void
+ipa_prop_write_all_agg_replacement (void)
+{
+  struct cgraph_node *node;
+  struct output_block *ob;
+  unsigned int count = 0;
+  lto_symtab_encoder_iterator lsei;
+  lto_symtab_encoder_t encoder;
+
+  if (!ipa_node_agg_replacements)
+    return;
+
+  ob = create_output_block (LTO_section_ipcp_transform);
+  encoder = ob->decl_state->symtab_node_encoder;
+  ob->cgraph_node = NULL;
+  for (lsei = lsei_start_function_in_partition (encoder); !lsei_end_p (lsei);
+       lsei_next_function_in_partition (&lsei))
+    {
+      node = lsei_cgraph_node (lsei);
+      if (cgraph_function_with_gimple_body_p (node)
+         && ipa_get_agg_replacements_for_node (node) != NULL)
+       count++;
+    }
+
+  streamer_write_uhwi (ob, count);
+
+  for (lsei = lsei_start_function_in_partition (encoder); !lsei_end_p (lsei);
+       lsei_next_function_in_partition (&lsei))
+    {
+      node = lsei_cgraph_node (lsei);
+      if (cgraph_function_with_gimple_body_p (node)
+         && ipa_get_agg_replacements_for_node (node) != NULL)
+       write_agg_replacement_chain (ob, node);
+    }
+  streamer_write_char_stream (ob->main_stream, 0);
+  produce_asm (ob, NULL);
+  destroy_output_block (ob);
+}
+
+/* Read replacements section in file FILE_DATA of length LEN with data
+   DATA.  */
+
+static void
+read_replacements_section (struct lto_file_decl_data *file_data,
+                          const char *data,
+                          size_t len)
+{
+  const struct lto_function_header *header =
+    (const struct lto_function_header *) 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;
+  struct lto_input_block ib_main;
+  unsigned int i;
+  unsigned int count;
+
+  LTO_INIT_INPUT_BLOCK (ib_main, (const char *) data + main_offset, 0,
+                       header->main_size);
+
+  data_in = lto_data_in_create (file_data, (const char *) data + string_offset,
+                               header->string_size, vNULL);
+  count = streamer_read_uhwi (&ib_main);
+
+  for (i = 0; i < count; i++)
+    {
+      unsigned int index;
+      struct cgraph_node *node;
+      lto_symtab_encoder_t encoder;
+
+      index = streamer_read_uhwi (&ib_main);
+      encoder = file_data->symtab_node_encoder;
+      node = cgraph (lto_symtab_encoder_deref (encoder, index));
+      gcc_assert (node->analyzed);
+      read_agg_replacement_chain (&ib_main, node, data_in);
+    }
+  lto_free_section_data (file_data, LTO_section_jump_functions, NULL, data,
+                        len);
+  lto_data_in_delete (data_in);
+}
+
+/* Read IPA-CP aggregate replacements.  */
+
+void
+ipa_prop_read_all_agg_replacement (void)
+{
+  struct lto_file_decl_data **file_data_vec = lto_get_file_decl_data ();
+  struct lto_file_decl_data *file_data;
+  unsigned int j = 0;
+
+  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);
+      if (data)
+        read_replacements_section (file_data, data, len);
+    }
+}
+
+/* Adjust the aggregate replacements in AGGVAL to reflect parameters skipped in
+   NODE.  */
+
+static void
+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)
+    return;
+
+  for (v = aggval; v; v = v->next)
+    {
+      gcc_assert (v->index >= 0);
+      if (c < v->index)
+       c = v->index;
+    }
+  c++;
+
+  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];
+}
+
+
+/* Function body transformation phase.  */
+
+unsigned int
+ipcp_transform_function (struct cgraph_node *node)
+{
+  vec<ipa_param_descriptor_t> descriptors = vNULL;
+  struct param_analysis_info *parms_ainfo;
+  struct ipa_agg_replacement_value *aggval;
+  gimple_stmt_iterator gsi;
+  basic_block bb;
+  int param_count;
+  bool cfg_changed = false, something_changed = false;
+
+  gcc_checking_assert (cfun);
+  gcc_checking_assert (current_function_decl);
+
+  if (dump_file)
+    fprintf (dump_file, "Modification phase of node %s/%i\n",
+            cgraph_node_name (node), node->uid);
+
+  aggval = ipa_get_agg_replacements_for_node (node);
+  if (!aggval)
+      return 0;
+  param_count = count_formal_params (node->symbol.decl);
+  if (param_count == 0)
+    return 0;
+  adjust_agg_replacement_values (node, aggval);
+  if (dump_file)
+    ipa_dump_agg_replacement_values (dump_file, aggval);
+  parms_ainfo = XALLOCAVEC (struct param_analysis_info, param_count);
+  memset (parms_ainfo, 0, sizeof (struct param_analysis_info) * param_count);
+  descriptors.safe_grow_cleared (param_count);
+  ipa_populate_param_decls (node, descriptors);
+
+  FOR_EACH_BB (bb)
+    for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
+      {
+       struct ipa_agg_replacement_value *v;
+       gimple stmt = gsi_stmt (gsi);
+       tree rhs, val, t;
+       HOST_WIDE_INT offset;
+       int index;
+       bool by_ref, vce;
+
+       if (!gimple_assign_load_p (stmt))
+         continue;
+       rhs = gimple_assign_rhs1 (stmt);
+       if (!is_gimple_reg_type (TREE_TYPE (rhs)))
+         continue;
+
+       vce = false;
+       t = rhs;
+       while (handled_component_p (t))
+         {
+           /* 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)
+             {
+               vce = true;
+               break;
+             }
+           t = TREE_OPERAND (t, 0);
+         }
+       if (vce)
+         continue;
+
+       if (!ipa_load_from_parm_agg_1 (descriptors, parms_ainfo, stmt,
+                                      rhs, &index, &offset, &by_ref))
+         continue;
+       for (v = aggval; v; v = v->next)
+         if (v->index == index
+             && v->offset == offset)
+           break;
+       if (!v)
+         continue;
+
+       gcc_checking_assert (is_gimple_ip_invariant (v->value));
+       if (!useless_type_conversion_p (TREE_TYPE (rhs), TREE_TYPE (v->value)))
+         {
+           if (fold_convertible_p (TREE_TYPE (rhs), v->value))
+             val = fold_build1 (NOP_EXPR, TREE_TYPE (rhs), v->value);
+           else if (TYPE_SIZE (TREE_TYPE (rhs))
+                    == TYPE_SIZE (TREE_TYPE (v->value)))
+             val = fold_build1 (VIEW_CONVERT_EXPR, TREE_TYPE (rhs), v->value);
+           else
+             {
+               if (dump_file)
+                 {
+                   fprintf (dump_file, "    const ");
+                   print_generic_expr (dump_file, v->value, 0);
+                   fprintf (dump_file, "  can't be converted to type of ");
+                   print_generic_expr (dump_file, rhs, 0);
+                   fprintf (dump_file, "\n");
+                 }
+               continue;
+             }
+         }
+       else
+         val = v->value;
+
+       if (dump_file && (dump_flags & TDF_DETAILS))
+         {
+           fprintf (dump_file, "Modifying stmt:\n  ");
+           print_gimple_stmt (dump_file, stmt, 0, 0);
+         }
+       gimple_assign_set_rhs_from_tree (&gsi, val);
+       update_stmt (stmt);
+
+       if (dump_file && (dump_flags & TDF_DETAILS))
+         {
+           fprintf (dump_file, "into:\n  ");
+           print_gimple_stmt (dump_file, stmt, 0, 0);
+           fprintf (dump_file, "\n");
+         }
+
+       something_changed = true;
+       if (maybe_clean_eh_stmt (stmt)
+           && gimple_purge_dead_eh_edges (gimple_bb (stmt)))
+         cfg_changed = true;
+      }
+
+  (*ipa_node_agg_replacements)[node->uid] = NULL;
+  free_parms_ainfo (parms_ainfo, param_count);
+  descriptors.release ();
+
+  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;
 }
 }