OSDN Git Service

Daily bump.
[pf3gnuchains/gcc-fork.git] / gcc / ipa-prop.c
index c482165..0064229 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.
@@ -38,6 +38,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-pretty-print.h"
 #include "gimple-pretty-print.h"
 #include "lto-streamer.h"
 #include "tree-pretty-print.h"
 #include "gimple-pretty-print.h"
 #include "lto-streamer.h"
+#include "data-streamer.h"
+#include "tree-streamer.h"
 
 
 /* Intermediate information about a parameter that is only useful during the
 
 
 /* Intermediate information about a parameter that is only useful during the
@@ -54,86 +56,24 @@ VEC (ipa_node_params_t, heap) *ipa_node_params_vector;
 /* Vector where the parameter infos are actually stored. */
 VEC (ipa_edge_args_t, gc) *ipa_edge_args_vector;
 
 /* 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;
-
 /* 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.  */
 
 
 /* Return index of the formal whose tree is PTREE in function which corresponds
    to INFO.  */
 
-static int
+int
 ipa_get_param_decl_index (struct ipa_node_params *info, tree ptree)
 {
   int i, count;
 
   count = ipa_get_param_count (info);
   for (i = 0; i < count; i++)
 ipa_get_param_decl_index (struct ipa_node_params *info, tree ptree)
 {
   int i, count;
 
   count = ipa_get_param_count (info);
   for (i = 0; i < count; i++)
-    if (ipa_get_param(info, i) == ptree)
+    if (ipa_get_param (info, i) == ptree)
       return i;
 
   return -1;
       return i;
 
   return -1;
@@ -156,7 +96,8 @@ ipa_populate_param_decls (struct cgraph_node *node,
   param_num = 0;
   for (parm = fnargs; parm; parm = DECL_CHAIN (parm))
     {
   param_num = 0;
   for (parm = fnargs; parm; parm = DECL_CHAIN (parm))
     {
-      info->params[param_num].decl = parm;
+      VEC_index (ipa_param_descriptor_t,
+                info->descriptors, param_num)->decl = parm;
       param_num++;
     }
 }
       param_num++;
     }
 }
@@ -164,7 +105,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 +116,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 +125,18 @@ 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)
     {
     {
-      ipa_count_formal_params (node, info);
-      info->params = XCNEWVEC (struct ipa_param_descriptor,
-                                   ipa_get_param_count (info));
-      ipa_populate_param_decls (node, info);
-    }
-}
-
-/* Count number of arguments callsite CS has and store it in
-   ipa_edge_args structure corresponding to this callsite.  */
+      int param_count;
 
 
-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->decl);
+      if (param_count)
+       {
+         VEC_safe_grow_cleared (ipa_param_descriptor_t, heap,
+                                info->descriptors, param_count);
+         ipa_populate_param_decls (node, info);
+       }
+    }
 }
 
 /* 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 +160,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)
        {
@@ -281,9 +197,9 @@ ipa_print_node_jump_functions_for_edge (FILE *f, struct cgraph_edge *cs)
                   tree_code_name[(int)
                                  jump_func->value.pass_through.operation]);
          if (jump_func->value.pass_through.operation != NOP_EXPR)
                   tree_code_name[(int)
                                  jump_func->value.pass_through.operation]);
          if (jump_func->value.pass_through.operation != NOP_EXPR)
-           print_generic_expr (dump_file,
+           print_generic_expr (f,
                                jump_func->value.pass_through.operand, 0);
                                jump_func->value.pass_through.operand, 0);
-         fprintf (dump_file, "\n");
+         fprintf (f, "\n");
        }
       else if (type == IPA_JF_ANCESTOR)
        {
        }
       else if (type == IPA_JF_ANCESTOR)
        {
@@ -292,7 +208,7 @@ 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");
+         fprintf (f, "\n");
        }
     }
 }
        }
     }
 }
@@ -314,8 +230,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);
     }
 
@@ -355,8 +271,20 @@ ipa_print_all_jump_functions (FILE *f)
 
 struct type_change_info
 {
 
 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.
@@ -405,17 +333,67 @@ stmt_may_be_vtbl_ptr_store (gimple stmt)
     {
       tree lhs = gimple_assign_lhs (stmt);
 
     {
       tree lhs = gimple_assign_lhs (stmt);
 
-      if (TREE_CODE (lhs) == COMPONENT_REF
-         && !DECL_VIRTUAL_P (TREE_OPERAND (lhs, 1))
-         && !AGGREGATE_TYPE_P (TREE_TYPE (lhs)))
+      if (!AGGREGATE_TYPE_P (TREE_TYPE (lhs)))
+       {
+         if (flag_strict_aliasing
+             && !POINTER_TYPE_P (TREE_TYPE (lhs)))
            return false;
            return false;
-      /* In the future we might want to use get_base_ref_and_offset to find
-        if there is a field corresponding to the offset and if so, proceed
-        almost like if it was a component ref.  */
+
+         if (TREE_CODE (lhs) == COMPONENT_REF
+             && !DECL_VIRTUAL_P (TREE_OPERAND (lhs, 1)))
+           return false;
+         /* In the future we might want to use get_base_ref_and_offset to find
+            if there is a field corresponding to the offset and if so, proceed
+            almost like if it was a component ref.  */
+       }
     }
   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
@@ -430,6 +408,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;
     }
@@ -437,16 +421,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;
@@ -459,25 +442,51 @@ 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
+    {
+      jfunc->type = IPA_JF_KNOWN_TYPE;
+      jfunc->value.known_type.base_type = tci.known_current_type;
+      jfunc->value.known_type.component_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).  */
@@ -485,43 +494,169 @@ 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 the formal parameter PARM might have been modified in this
+   function before reaching the statement STMT.  PARM_AINFO is a pointer to a
+   structure containing temporary information about PARM.  */
 
 
-  return detect_type_change (arg, arg, call, jfunc, 0);
+static bool
+is_parm_modified_before_stmt (struct param_analysis_info *parm_ainfo,
+                             gimple stmt, tree parm)
+{
+  bool modified = false;
+  ao_ref refd;
+
+  if (parm_ainfo->modified)
+    return true;
+
+  gcc_checking_assert (gimple_vuse (stmt) != NULL_TREE);
+  ao_ref_init (&refd, parm);
+  walk_aliased_vdefs (&refd, gimple_vuse (stmt), mark_modified,
+                     &modified, &parm_ainfo->visited_statements);
+  if (modified)
+    {
+      parm_ainfo->modified = true;
+      return true;
+    }
+  return false;
 }
 
 }
 
+/* If STMT is an assignment that loads a value from an parameter declaration,
+   return the index of the parameter in ipa_node_params which has not been
+   modified.  Otherwise return -1.  */
+
+static int
+load_from_unmodified_param (struct ipa_node_params *info,
+                           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 (info, op1);
+  if (index < 0
+      || is_parm_modified_before_stmt (&parms_ainfo[index], stmt, op1))
+    return -1;
+
+  return index;
+}
 
 /* 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, parms_ainfo,
+                                           SSA_NAME_DEF_STMT (op1));
+      tc_ssa = op1;
+    }
+  else
+    {
+      index = load_from_unmodified_param (info, parms_ainfo, stmt);
+      tc_ssa = gimple_assign_lhs (stmt);
+    }
+
+  if (index >= 0)
+    {
+      tree op2 = gimple_assign_rhs2 (stmt);
 
       if (op2)
        {
 
       if (op2)
        {
@@ -536,8 +671,8 @@ compute_complex_assign_jump_func (struct ipa_node_params *info,
          jfunc->value.pass_through.operation = gimple_assign_rhs_code (stmt);
          jfunc->value.pass_through.operand = op2;
        }
          jfunc->value.pass_through.operation = gimple_assign_rhs_code (stmt);
          jfunc->value.pass_through.operand = op2;
        }
-      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->type = IPA_JF_PASS_THROUGH;
          jfunc->value.pass_through.formal_id = index;
@@ -714,7 +849,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
@@ -730,30 +865,28 @@ compute_known_type_jump_func (tree op, struct ipa_jump_func *jfunc,
       || is_global_var (base))
     return;
 
       || is_global_var (base))
     return;
 
-  if (detect_type_change (op, base, call, jfunc, offset))
+  if (!TYPE_BINFO (TREE_TYPE (base))
+      || detect_type_change (op, base, call, jfunc, offset))
     return;
 
     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;
-    }
+  jfunc->type = IPA_JF_KNOWN_TYPE;
+  jfunc->value.known_type.base_type = TREE_TYPE (base);
+  jfunc->value.known_type.offset = offset;
+  jfunc->value.known_type.component_type = TREE_TYPE (op);
 }
 
 
 /* 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
 }
 
 
 /* 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.*/
+   structure associated with the caller, PARMS_AINFO describes state of
+   analysis with respect to individual formal parameters.  ARGS is the
+   ipa_edge_args structure describing the callsite CALL which is the call
+   statement being examined.*/
 
 static void
 compute_scalar_jump_functions (struct ipa_node_params *info,
 
 static void
 compute_scalar_jump_functions (struct ipa_node_params *info,
-                              struct ipa_jump_func *functions,
+                              struct param_analysis_info *parms_ainfo,
+                              struct ipa_edge_args *args,
                               gimple call)
 {
   tree arg;
                               gimple call)
 {
   tree arg;
@@ -761,12 +894,13 @@ compute_scalar_jump_functions (struct ipa_node_params *info,
 
   for (num = 0; num < gimple_call_num_args (call); num++)
     {
 
   for (num = 0; num < gimple_call_num_args (call); num++)
     {
+      struct ipa_jump_func *jfunc = ipa_get_ith_jump_func (args, num);
       arg = gimple_call_arg (call, num);
 
       if (is_gimple_ip_invariant (arg))
        {
       arg = gimple_call_arg (call, num);
 
       if (is_gimple_ip_invariant (arg))
        {
-         functions[num].type = IPA_JF_CONST;
-         functions[num].value.constant = arg;
+         jfunc->type = IPA_JF_CONST;
+         jfunc->value.constant = arg;
        }
       else if (TREE_CODE (arg) == SSA_NAME)
        {
        }
       else if (TREE_CODE (arg) == SSA_NAME)
        {
@@ -775,26 +909,25 @@ compute_scalar_jump_functions (struct ipa_node_params *info,
              int index = ipa_get_param_decl_index (info, SSA_NAME_VAR (arg));
 
              if (index >= 0
              int index = ipa_get_param_decl_index (info, SSA_NAME_VAR (arg));
 
              if (index >= 0
-                 && !detect_type_change_ssa (arg, call, &functions[num]))
+                 && !detect_type_change_ssa (arg, call, jfunc))
                {
                {
-                 functions[num].type = IPA_JF_PASS_THROUGH;
-                 functions[num].value.pass_through.formal_id = index;
-                 functions[num].value.pass_through.operation = NOP_EXPR;
+                 jfunc->type = IPA_JF_PASS_THROUGH;
+                 jfunc->value.pass_through.formal_id = index;
+                 jfunc->value.pass_through.operation = NOP_EXPR;
                }
            }
          else
            {
              gimple stmt = SSA_NAME_DEF_STMT (arg);
              if (is_gimple_assign (stmt))
                }
            }
          else
            {
              gimple stmt = SSA_NAME_DEF_STMT (arg);
              if (is_gimple_assign (stmt))
-               compute_complex_assign_jump_func (info, &functions[num],
+               compute_complex_assign_jump_func (info, parms_ainfo, jfunc,
                                                  call, stmt, arg);
              else if (gimple_code (stmt) == GIMPLE_PHI)
                                                  call, stmt, arg);
              else if (gimple_code (stmt) == GIMPLE_PHI)
-               compute_complex_ancestor_jump_func (info, &functions[num],
-                                                   call, stmt);
+               compute_complex_ancestor_jump_func (info, jfunc, call, stmt);
            }
        }
       else
            }
        }
       else
-       compute_known_type_jump_func (arg, &functions[num], call);
+       compute_known_type_jump_func (arg, jfunc, call);
     }
 }
 
     }
 }
 
@@ -831,43 +964,6 @@ 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
 /* 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
@@ -877,8 +973,8 @@ is_parm_modified_before_call (struct param_analysis_info *parm_info,
 
 static bool
 compute_pass_through_member_ptrs (struct ipa_node_params *info,
 
 static bool
 compute_pass_through_member_ptrs (struct ipa_node_params *info,
-                                 struct param_analysis_info *parms_info,
-                                 struct ipa_jump_func *functions,
+                                 struct param_analysis_info *parms_ainfo,
+                                 struct ipa_edge_args *args,
                                  gimple call)
 {
   bool undecided_members = false;
                                  gimple call)
 {
   bool undecided_members = false;
@@ -896,11 +992,14 @@ compute_pass_through_member_ptrs (struct ipa_node_params *info,
              int index = ipa_get_param_decl_index (info, arg);
 
              gcc_assert (index >=0);
              int index = ipa_get_param_decl_index (info, arg);
 
              gcc_assert (index >=0);
-             if (!is_parm_modified_before_call (&parms_info[index], call, arg))
+             if (!is_parm_modified_before_stmt (&parms_ainfo[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;
+                 struct ipa_jump_func *jfunc = ipa_get_ith_jump_func (args,
+                                                                      num);
+                 jfunc->type = IPA_JF_PASS_THROUGH;
+                 jfunc->value.pass_through.formal_id = index;
+                 jfunc->value.pass_through.operation = NOP_EXPR;
                }
              else
                undecided_members = true;
                }
              else
                undecided_members = true;
@@ -1026,7 +1125,7 @@ determine_cst_member_ptr (gimple call, tree arg, tree method_field,
    associated with the call.  */
 
 static void
    associated with the call.  */
 
 static void
-compute_cst_member_ptr_arguments (struct ipa_jump_func *functions,
+compute_cst_member_ptr_arguments (struct ipa_edge_args *args,
                                  gimple call)
 {
   unsigned num;
                                  gimple call)
 {
   unsigned num;
@@ -1034,13 +1133,13 @@ compute_cst_member_ptr_arguments (struct ipa_jump_func *functions,
 
   for (num = 0; num < gimple_call_num_args (call); num++)
     {
 
   for (num = 0; num < gimple_call_num_args (call); num++)
     {
+      struct ipa_jump_func *jfunc = ipa_get_ith_jump_func (args, num);
       arg = gimple_call_arg (call, num);
 
       arg = gimple_call_arg (call, num);
 
-      if (functions[num].type == IPA_JF_UNKNOWN
+      if (jfunc->type == IPA_JF_UNKNOWN
          && type_like_member_ptr_p (TREE_TYPE (arg), &method_field,
                                     &delta_field))
          && type_like_member_ptr_p (TREE_TYPE (arg), &method_field,
                                     &delta_field))
-       determine_cst_member_ptr (call, arg, method_field, delta_field,
-                                 &functions[num]);
+       determine_cst_member_ptr (call, arg, method_field, delta_field, jfunc);
     }
 }
 
     }
 }
 
@@ -1049,33 +1148,29 @@ 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 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));
-
-  call = cs->call_stmt;
-  gcc_assert (is_gimple_call (call));
+  VEC_safe_grow_cleared (ipa_jump_func_t, gc, args->jump_functions, arg_num);
 
   /* We will deal with constants and SSA scalars first:  */
 
   /* We will deal with constants and SSA scalars first:  */
-  compute_scalar_jump_functions (info, arguments->jump_functions, call);
+  compute_scalar_jump_functions (info, parms_ainfo, args, call);
 
   /* Let's check whether there are any potential member pointers and if so,
      whether we can determine their functions as pass_through.  */
 
   /* 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))
+  if (!compute_pass_through_member_ptrs (info, parms_ainfo, args, call))
     return;
 
   /* Finally, let's check whether we actually pass a new constant member
      pointer here...  */
     return;
 
   /* Finally, let's check whether we actually pass a new constant member
      pointer here...  */
-  compute_cst_member_ptr_arguments (arguments->jump_functions, call);
+  compute_cst_member_ptr_arguments (args, call);
 }
 
 /* Compute jump functions for all edges - both direct and indirect - outgoing
 }
 
 /* Compute jump functions for all edges - both direct and indirect - outgoing
@@ -1083,32 +1178,23 @@ 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
 }
 
 /* If RHS looks like a rhs of a statement loading pfn from a member
@@ -1205,7 +1291,7 @@ ipa_note_param_call (struct cgraph_node *node, int param_index, gimple stmt)
 }
 
 /* Analyze the CALL and examine uses of formal parameters of the caller NODE
 }
 
 /* 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
@@ -1264,7 +1350,7 @@ ipa_note_param_call (struct cgraph_node *node, int param_index, gimple stmt)
 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;
@@ -1339,7 +1425,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,7 +1463,7 @@ ipa_analyze_indirect_call_uses (struct cgraph_node *node,
     return;
 
   index = ipa_get_param_decl_index (info, rec);
     return;
 
   index = ipa_get_param_decl_index (info, rec);
-  if (index >= 0 && !is_parm_modified_before_call (&parms_info[index],
+  if (index >= 0 && !is_parm_modified_before_stmt (&parms_ainfo[index],
                                                   call, rec))
     ipa_note_param_call (node, index, call);
 
                                                   call, rec))
     ipa_note_param_call (node, index, call);
 
@@ -1440,18 +1527,20 @@ ipa_analyze_virtual_call_uses (struct cgraph_node *node,
 }
 
 /* Analyze a call statement CALL whether and how it utilizes formal parameters
 }
 
 /* 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);
 
 {
   tree target = gimple_call_fn (call);
 
+  if (!target)
+    return;
   if (TREE_CODE (target) == SSA_NAME)
   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);
 }
@@ -1459,15 +1548,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.
@@ -1486,7 +1575,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;
@@ -1494,12 +1583,12 @@ 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;
   basic_block bb;
 {
   tree decl = node->decl;
   basic_block bb;
@@ -1518,7 +1607,7 @@ ipa_analyze_params_uses (struct cgraph_node *node,
         the flag during modification analysis.  */
       if (is_gimple_reg (parm)
          && gimple_default_def (DECL_STRUCT_FUNCTION (node->decl), parm))
         the flag during modification analysis.  */
       if (is_gimple_reg (parm)
          && gimple_default_def (DECL_STRUCT_FUNCTION (node->decl), parm))
-       info->params[i].used = true;
+       ipa_set_param_used (info, i, true);
     }
 
   func = DECL_STRUCT_FUNCTION (decl);
     }
 
   func = DECL_STRUCT_FUNCTION (decl);
@@ -1531,7 +1620,7 @@ 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,
          walk_stmt_load_store_addr_ops (stmt, info,
                                         visit_ref_for_mod_analysis,
                                         visit_ref_for_mod_analysis,
@@ -1555,7 +1644,7 @@ 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;
+  struct param_analysis_info *parms_ainfo;
   int i, param_count;
 
   ipa_check_create_node_params ();
   int i, param_count;
 
   ipa_check_create_node_params ();
@@ -1566,15 +1655,15 @@ ipa_analyze_node (struct cgraph_node *node)
   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);
+  ipa_analyze_params_uses (node, parms_ainfo);
+  ipa_compute_jump_functions (node, parms_ainfo);
 
   for (i = 0; i < param_count; i++)
 
   for (i = 0; i < param_count; i++)
-    if (parms_info[i].visited_statements)
-      BITMAP_FREE (parms_info[i].visited_statements);
+    if (parms_ainfo[i].visited_statements)
+      BITMAP_FREE (parms_ainfo[i].visited_statements);
 
   current_function_decl = NULL;
   pop_cfun ();
 
   current_function_decl = NULL;
   pop_cfun ();
@@ -1589,18 +1678,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 = src->value.known_type.offset + dst->value.ancestor.offset;
+  combined_type = dst->value.ancestor.type;
+
+  dst->type = IPA_JF_KNOWN_TYPE;
+  dst->value.known_type.base_type = src->value.known_type.base_type;
+  dst->value.known_type.offset = combined_offset;
+  dst->value.known_type.component_type = 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
@@ -1667,12 +1754,10 @@ 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;
 
@@ -1685,34 +1770,24 @@ 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);
   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;
 }
@@ -1735,7 +1810,7 @@ try_make_edge_direct_simple_call (struct cgraph_edge *ie,
   else
     return NULL;
 
   else
     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
 }
 
 /* Try to find a destination for indirect edge IE that corresponds to a
@@ -1747,27 +1822,24 @@ static struct cgraph_edge *
 try_make_edge_direct_virtual_call (struct cgraph_edge *ie,
                                   struct ipa_jump_func *jfunc)
 {
 try_make_edge_direct_virtual_call (struct cgraph_edge *ie,
                                   struct ipa_jump_func *jfunc)
 {
-  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
+  if (jfunc->type != IPA_JF_KNOWN_TYPE)
     return NULL;
 
     return NULL;
 
-  if (!binfo)
-    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 = TYPE_BINFO (jfunc->value.known_type.base_type);
+  gcc_checking_assert (binfo);
+  binfo = get_binfo_at_offset (binfo, jfunc->value.known_type.offset
+                              + ie->indirect_info->anc_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;
 }
@@ -1796,18 +1868,14 @@ update_indirect_edges_after_inlining (struct cgraph_edge *cs,
       struct ipa_jump_func *jfunc;
 
       next_ie = ie->next_callee;
       struct ipa_jump_func *jfunc;
 
       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;
        }
 
@@ -1822,7 +1890,10 @@ update_indirect_edges_after_inlining (struct cgraph_edge *cs,
        }
       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)
        new_direct_edge = try_make_edge_direct_virtual_call (ie, jfunc);
 
       if (ici->polymorphic)
        new_direct_edge = try_make_edge_direct_virtual_call (ie, jfunc);
@@ -1832,6 +1903,10 @@ update_indirect_edges_after_inlining (struct cgraph_edge *cs,
       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->decl);
          if (new_edges)
            {
              VEC_safe_push (cgraph_edge_p, heap, *new_edges,
          if (new_edges)
            {
              VEC_safe_push (cgraph_edge_p, heap, *new_edges,
@@ -1868,6 +1943,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;
 }
@@ -1882,17 +1959,19 @@ bool
 ipa_propagate_indirect_call_infos (struct cgraph_edge *cs,
                                   VEC (cgraph_edge_p, heap) **new_edges)
 {
 ipa_propagate_indirect_call_infos (struct cgraph_edge *cs,
                                   VEC (cgraph_edge_p, heap) **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).  */
   if (!ipa_node_params_vector)
     return false;
   gcc_assert (ipa_edge_args_vector);
 
   /* Do nothing if the preparation phase has not been carried out yet
      (i.e. during early inlining).  */
   if (!ipa_node_params_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
@@ -1928,9 +2007,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);
-
+  VEC_free (ipa_param_descriptor_t, heap, info->descriptors);
+  free (info->lattices);
+  /* Lattice values and their sources are deallocated with their alocation
+     pool.  */
+  VEC_free (tree, heap, info->known_vals);
   memset (info, 0, sizeof (*info));
 }
 
   memset (info, 0, sizeof (*info));
 }
 
@@ -1973,35 +2054,6 @@ ipa_node_removal_hook (struct cgraph_node *node, void *data ATTRIBUTE_UNUSED)
   ipa_free_node_params_substructures (IPA_NODE_REF (node));
 }
 
   ipa_free_node_params_substructures (IPA_NODE_REF (node));
 }
 
-/* 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.  */
 
 static void
 /* Hook that is called by cgraph.c when a node is duplicated.  */
 
 static void
@@ -2009,21 +2061,14 @@ ipa_edge_duplication_hook (struct cgraph_edge *src, struct cgraph_edge *dst,
                           __attribute__((unused)) void *data)
 {
   struct ipa_edge_args *old_args, *new_args;
                           __attribute__((unused)) void *data)
 {
   struct ipa_edge_args *old_args, *new_args;
-  int arg_count;
 
   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);
-
-  if (iinlining_processed_edges
-      && bitmap_bit_p (iinlining_processed_edges, src->uid))
-    bitmap_set_bit (iinlining_processed_edges, dst->uid);
+  new_args->jump_functions = VEC_copy (ipa_jump_func_t, gc,
+                                      old_args->jump_functions);
 }
 
 /* Hook that is called by cgraph.c when a node is duplicated.  */
 }
 
 /* Hook that is called by cgraph.c when a node is duplicated.  */
@@ -2033,28 +2078,29 @@ 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;
 
   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 = VEC_copy (ipa_param_descriptor_t, heap,
+                                   old_info->descriptors);
+  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;
 }
 
+
+/* 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.  */
 
 void
 /* Register our cgraph hooks if they are not already there.  */
 
 void
@@ -2072,6 +2118,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.  */
@@ -2087,14 +2135,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
@@ -2103,10 +2145,12 @@ 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);
       ipa_unregister_cgraph_hooks ();
     }
 }
       ipa_unregister_cgraph_hooks ();
     }
 }
@@ -2117,11 +2161,13 @@ 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);
 }
 
 /* Print ipa_tree_map data structures of all functions in the
 }
 
 /* Print ipa_tree_map data structures of all functions in the
@@ -2176,7 +2222,7 @@ ipa_get_vector_of_formal_parms (tree fndecl)
   int count;
   tree parm;
 
   int count;
   tree parm;
 
-  count = count_formal_params_1 (fndecl);
+  count = count_formal_params (fndecl);
   args = VEC_alloc (tree, heap, count);
   for (parm = DECL_ARGUMENTS (fndecl); parm; parm = DECL_CHAIN (parm))
     VEC_quick_push (tree, args, parm);
   args = VEC_alloc (tree, heap, count);
   for (parm = DECL_ARGUMENTS (fndecl); parm; parm = DECL_CHAIN (parm))
     VEC_quick_push (tree, args, parm);
@@ -2373,6 +2419,7 @@ ipa_modify_call_arguments (struct cgraph_edge *cs, gimple stmt,
                           ipa_parm_adjustment_vec adjustments)
 {
   VEC(tree, heap) *vargs;
                           ipa_parm_adjustment_vec adjustments)
 {
   VEC(tree, heap) *vargs;
+  VEC(tree, gc) **debug_args = NULL;
   gimple new_stmt;
   gimple_stmt_iterator gsi;
   tree callee_decl;
   gimple new_stmt;
   gimple_stmt_iterator gsi;
   tree callee_decl;
@@ -2380,6 +2427,7 @@ ipa_modify_call_arguments (struct cgraph_edge *cs, gimple stmt,
 
   len = VEC_length (ipa_parm_adjustment_t, adjustments);
   vargs = VEC_alloc (tree, heap, len);
 
   len = VEC_length (ipa_parm_adjustment_t, adjustments);
   vargs = VEC_alloc (tree, heap, len);
+  callee_decl = !cs ? gimple_call_fndecl (stmt) : cs->callee->decl;
 
   gsi = gsi_for_stmt (stmt);
   for (i = 0; i < len; i++)
 
   gsi = gsi_for_stmt (stmt);
   for (i = 0; i < len; i++)
@@ -2448,7 +2496,7 @@ ipa_modify_call_arguments (struct cgraph_edge *cs, gimple stmt,
                                       base_offset
                                       + adj->offset / BITS_PER_UNIT);
                  off = int_const_binop (PLUS_EXPR, TREE_OPERAND (base, 1),
                                       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
@@ -2460,9 +2508,27 @@ 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;
+             align = get_pointer_alignment_1 (base, &misalign);
+             misalign += (double_int_sext (tree_to_double_int (off),
+                                           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
 
          expr = force_gimple_operand_gsi (&gsi, expr,
                                           adj->by_ref
@@ -2470,6 +2536,42 @@ ipa_modify_call_arguments (struct cgraph_edge *cs, gimple stmt,
                                           NULL, true, GSI_SAME_STMT);
          VEC_quick_push (tree, vargs, expr);
        }
                                           NULL, true, GSI_SAME_STMT);
          VEC_quick_push (tree, vargs, 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_iterate (tree, *debug_args, ix, ddecl); ix += 2)
+           if (ddecl == origin)
+             {
+               ddecl = VEC_index (tree, *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 (tree, gc, *debug_args, origin);
+             VEC_safe_push (tree, gc, *debug_args, ddecl);
+           }
+         def_temp = gimple_build_debug_bind (ddecl, unshare_expr (arg),
+                                             stmt);
+         gsi_insert_before (&gsi, def_temp, GSI_SAME_STMT);
+       }
     }
 
   if (dump_file && (dump_flags & TDF_DETAILS))
     }
 
   if (dump_file && (dump_flags & TDF_DETAILS))
@@ -2478,7 +2580,6 @@ 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);
   VEC_free (tree, heap, vargs);
   if (gimple_call_lhs (stmt))
   new_stmt = gimple_build_call_vec (callee_decl, vargs);
   VEC_free (tree, heap, vargs);
   if (gimple_call_lhs (stmt))
@@ -2487,8 +2588,8 @@ ipa_modify_call_arguments (struct cgraph_edge *cs, gimple stmt,
   gimple_set_block (new_stmt, gimple_block (stmt));
   if (gimple_has_location (stmt))
     gimple_set_location (new_stmt, gimple_location (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))
     {
@@ -2665,36 +2766,33 @@ 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);
+  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);
+      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);
       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);
+      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);
       break;
     case IPA_JF_CONST_MEMBER_PTR:
       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);
+      stream_write_tree (ob, jump_func->value.member_cst.pfn, true);
+      stream_write_tree (ob, jump_func->value.member_cst.delta, false);
       break;
     }
 }
       break;
     }
 }
@@ -2706,31 +2804,35 @@ 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);
+  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);
       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);
+      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);
       break;
     case IPA_JF_CONST_MEMBER_PTR:
       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.member_cst.pfn = stream_read_tree (ib, data_in);
+      jump_func->value.member_cst.delta = stream_read_tree (ib, data_in);
       break;
     }
 }
       break;
     }
 }
@@ -2745,16 +2847,16 @@ 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->anc_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);
+  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);
     }
 }
 
     }
 }
 
@@ -2769,14 +2871,14 @@ 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->anc_offset = (HOST_WIDE_INT) streamer_read_hwi (ib);
+  bp = streamer_read_bitpack (ib);
   ii->polymorphic = bp_unpack_value (&bp, 1);
   if (ii->polymorphic)
     {
   ii->polymorphic = bp_unpack_value (&bp, 1);
   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,28 +2896,33 @@ ipa_write_node_info (struct output_block *ob, struct cgraph_node *node)
 
   encoder = ob->decl_state->cgraph_node_encoder;
   node_ref = lto_cgraph_encoder_encode (encoder, node);
 
   encoder = ob->decl_state->cgraph_node_encoder;
   node_ref = lto_cgraph_encoder_encode (encoder, node);
-  lto_output_uleb128_stream (ob->main_stream, node_ref);
+  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.  */
@@ -2831,29 +2938,39 @@ 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 (ipa_jump_func_t, gc, 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 (ipa_jump_func_t, gc, 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.  */
 }
 
 /* Write jump functions for nodes in SET.  */
@@ -2862,29 +2979,34 @@ void
 ipa_prop_write_jump_functions (cgraph_node_set set)
 {
   struct cgraph_node *node;
 ipa_prop_write_jump_functions (cgraph_node_set set)
 {
   struct cgraph_node *node;
-  struct output_block *ob = create_output_block (LTO_section_jump_functions);
+  struct output_block *ob;
   unsigned int count = 0;
   cgraph_node_set_iterator csi;
 
   unsigned int count = 0;
   cgraph_node_set_iterator csi;
 
-  ob->cgraph_node = NULL;
+  if (!ipa_node_params_vector)
+    return;
 
 
+  ob = create_output_block (LTO_section_jump_functions);
+  ob->cgraph_node = NULL;
   for (csi = csi_start (set); !csi_end_p (csi); csi_next (&csi))
     {
       node = csi_node (csi);
   for (csi = csi_start (set); !csi_end_p (csi); csi_next (&csi))
     {
       node = csi_node (csi);
-      if (node->analyzed && IPA_NODE_REF (node) != NULL)
+      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.  */
   for (csi = csi_start (set); !csi_end_p (csi); csi_next (&csi))
     {
       node = csi_node (csi);
 
   /* Process all of the functions.  */
   for (csi = csi_start (set); !csi_end_p (csi); csi_next (&csi))
     {
       node = csi_node (csi);
-      if (node->analyzed && IPA_NODE_REF (node) != NULL)
+      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);
 }
@@ -2897,9 +3019,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;
@@ -2911,7 +3033,7 @@ 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,
                        header->string_size, NULL);
   data_in =
     lto_data_in_create (file_data, (const char *) data + string_offset,
                        header->string_size, NULL);
-  count = lto_input_uleb128 (&ib_main);
+  count = streamer_read_uhwi (&ib_main);
 
   for (i = 0; i < count; i++)
     {
 
   for (i = 0; i < count; i++)
     {
@@ -2919,7 +3041,7 @@ ipa_prop_read_section (struct lto_file_decl_data *file_data, const char *data,
       struct cgraph_node *node;
       lto_cgraph_encoder_t encoder;
 
       struct cgraph_node *node;
       lto_cgraph_encoder_t encoder;
 
-      index = lto_input_uleb128 (&ib_main);
+      index = streamer_read_uhwi (&ib_main);
       encoder = file_data->cgraph_node_encoder;
       node = lto_cgraph_encoder_deref (encoder, index);
       gcc_assert (node->analyzed);
       encoder = file_data->cgraph_node_encoder;
       node = lto_cgraph_encoder_deref (encoder, index);
       gcc_assert (node->analyzed);
@@ -2961,7 +3083,6 @@ 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 ();
@@ -2969,13 +3090,4 @@ ipa_update_after_lto_read (void)
   for (node = cgraph_nodes; node; node = node->next)
     if (node->analyzed)
       ipa_initialize_node_params (node);
   for (node = cgraph_nodes; node; node = node->next)
     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));
-       }
 }
 }