public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [PATCH] Make ipa-prop analyze BBs in DOM order
@ 2014-04-25 15:30 Martin Jambor
  2014-04-28  9:05 ` Richard Biener
  2014-05-15 18:42 ` Jan Hubicka
  0 siblings, 2 replies; 5+ messages in thread
From: Martin Jambor @ 2014-04-25 15:30 UTC (permalink / raw)
  To: GCC Patches; +Cc: Jan Hubicka

Hi,

the following patch deals with requested propagation in PR 53787 in
the real benchmark (as opposed to the original simple testcase) by
analyzing individual BBs in ipa-prop.c in dominator order.

Currently we do the analysis in two loops, in the first the order is
given by FOR_EACH_BB_FN and in the second the order is the order of
call graph edges (which in practice is quite bad because we tend to
start with BBs towards the end).  When analysis determines that a
non-SSA parameter or that data pointed to by a parameter are modified,
this is marked into a function wide flag (describing the parameter)
and we always consider the data clobbered from that moment on in order
to save AA walking.

This patch changes the analysis into dominator order and data is
considered clobbered only in dominator children of a block where it
was determined to be possibly clobbered, not in the whole function.
This was confirmed to help in the aforementioned PR.

The patch also, enforces a cap on the number of statements walked
(approx. 4 times the highest I have ever seen).  On the other hand it
gives up trying to cache the bitmap of visited memory-SSAs.  The
per-BB information had to be put somewhere and I took this opportunity
to cram a lot of commonly used per-function data into the same
structure, which is then passed among various functions.  The new
structure replaces the struct param_analysis_info.

Bootstrapped and tested on x86_64-linux, I have also LTO-built Firefox
at -O3 with it.  OK for trunk?

Thanks,

Martin


2014-02-12  Martin Jambor  <mjambor@suse.cz>

	PR tree-optimization/53787
	* params.def (PARAM_IPA_CP_LOOP_HINT_BONUS): New param.
	* ipa-prop.h (ipa_node_params): Rename uses_analysis_done to
	analysis_done, update all uses.
	* ipa-prop.c: Include domwalk.h
	(param_analysis_info): Removed.
	(param_aa_status): New type.
	(ipa_bb_info): Likewise.
	(func_body_info): Likewise.
	(ipa_get_bb_info): New function.
	(aa_overwalked): Likewise.
	(find_dominating_aa_status): Likewise.
	(parm_bb_aa_status_for_bb): Likewise.
	(parm_preserved_before_stmt_p): Changed to use new param AA info.
	(load_from_unmodified_param): Accept func_body_info as a parameter
	instead of parms_ainfo.
	(parm_ref_data_preserved_p): Changed to use new param AA info.
	(parm_ref_data_pass_through_p): Likewise.
	(ipa_load_from_parm_agg_1): Likewise.  Update callers.
	(compute_complex_assign_jump_func): Changed to use new param AA info.
	(compute_complex_ancestor_jump_func): Likewise.
	(ipa_compute_jump_functions_for_edge): Likewise.
	(ipa_compute_jump_functions): Removed.
	(ipa_compute_jump_functions_for_bb): New function.
	(ipa_analyze_indirect_call_uses): Likewise, moved variable
	declarations down.
	(ipa_analyze_virtual_call_uses): Accept func_body_info instead of node
	and info, moved variable declarations down.
	(ipa_analyze_call_uses): Accept and pass on func_body_info instead of
	node and info.
	(ipa_analyze_stmt_uses): Likewise.
	(ipa_analyze_params_uses): Removed.
	(ipa_analyze_params_uses_in_bb): New function.
	(ipa_analyze_controlled_uses): Likewise.
	(free_ipa_bb_info): Likewise.
	(analysis_dom_walker): New class.
	(ipa_analyze_node): Handle node-specific forbidden analysis,
	initialize and free func_body_info, use dominator walker.
	(ipcp_modif_dom_walker): New class.
	(ipcp_transform_function): Create and free func_body_info, use
	ipcp_modif_dom_walker, moved a lot of functionality there.

Index: src/gcc/ipa-prop.c
===================================================================
*** src.orig/gcc/ipa-prop.c
--- src/gcc/ipa-prop.c
*************** along with GCC; see the file COPYING3.
*** 59,72 ****
  #include "ipa-utils.h"
  #include "stringpool.h"
  #include "tree-ssanames.h"
  
! /* Intermediate information about a parameter that is only useful during the
!    run of ipa_analyze_node and is not kept afterwards.  */
  
! struct param_analysis_info
  {
    bool parm_modified, ref_modified, pt_modified;
!   bitmap parm_visited_statements, pt_visited_statements;
  };
  
  /* Vector where the parameter infos are actually stored. */
--- 59,111 ----
  #include "ipa-utils.h"
  #include "stringpool.h"
  #include "tree-ssanames.h"
+ #include "domwalk.h"
  
! /* Intermediate information that we get from AA analysis about a parameter.  */
  
! struct param_aa_status
  {
+   /* If not true, look at the dominator parent instead.  */
+   bool valid;
+ 
+   /* Whether we have seen something which might have modified the data in
+      question.  Parm is for the parameter itself, ref is for data it points to
+      but using the alias type of individual accesses and pt is the same thing
+      but for computing aggregate pass-through functions using a very inclusive
+      ao_ref.  */
    bool parm_modified, ref_modified, pt_modified;
! };
! 
! /* Information related to a given BB that used only when looking at function
!    body.  */
! 
! struct ipa_bb_info
! {
!   /* Call graph edges going out of this BB.  */
!   vec<cgraph_edge_p> cg_edges;
!   /* Alias analysis statuses of each formal parameter at this bb.  */
!   vec<param_aa_status> paas;
! };
! 
! /* Structure with global information that is only used when looking at function
!    body. */
! 
! struct func_body_info
! {
!   /* The node that is being analyzed.  */
!   cgraph_node *node;
! 
!   /* Its info.  */
!   struct ipa_node_params *info;
! 
!   /* Information about individual BBs. */
!   vec<ipa_bb_info> ibbis;
! 
!   /* Number of parameters.  */
!   int param_count;
! 
!   /* Number of statements already walked by when analyzing this function.  */
!   unsigned int aa_walked;
  };
  
  /* Vector where the parameter infos are actually stored. */
*************** ipa_binfo_from_known_type_jfunc (struct
*** 510,515 ****
--- 549,564 ----
  			      jfunc->value.known_type.component_type);
  }
  
+ /* Get IPA BB information about the given BB.  FBI is the context of analyzis
+    of this function body.  */
+ 
+ static struct ipa_bb_info *
+ ipa_get_bb_info (struct func_body_info *fbi, basic_block bb)
+ {
+   gcc_checking_assert (fbi);
+   return &fbi->ibbis[bb->index];
+ }
+ 
  /* Structure to be passed in between detect_type_change and
     check_stmt_for_type_change.  */
  
*************** mark_modified (ao_ref *ao ATTRIBUTE_UNUS
*** 769,802 ****
    return true;
  }
  
  /* Return true if a load from a formal parameter PARM_LOAD is known to retrieve
     a value known not to be modified in this function before reaching the
!    statement STMT.  PARM_AINFO is a pointer to a structure containing temporary
!    information about the parameter.  */
  
  static bool
! parm_preserved_before_stmt_p (struct param_analysis_info *parm_ainfo,
! 			       gimple stmt, tree parm_load)
  {
    bool modified = false;
-   bitmap *visited_stmts;
    ao_ref refd;
  
!   if (parm_ainfo && parm_ainfo->parm_modified)
!     return false;
  
    gcc_checking_assert (gimple_vuse (stmt) != NULL_TREE);
    ao_ref_init (&refd, parm_load);
!   /* We can cache visited statements only when parm_ainfo is available and when
!      we are looking at a naked load of the whole parameter.  */
!   if (!parm_ainfo || TREE_CODE (parm_load) != PARM_DECL)
!     visited_stmts = NULL;
!   else
!     visited_stmts = &parm_ainfo->parm_visited_statements;
!   walk_aliased_vdefs (&refd, gimple_vuse (stmt), mark_modified, &modified,
! 		      visited_stmts);
!   if (parm_ainfo && modified)
!     parm_ainfo->parm_modified = true;
    return !modified;
  }
  
--- 818,918 ----
    return true;
  }
  
+ /* Return true if we have already walked so many statements in AA that we
+    should really just start giving up.  */
+ 
+ static bool
+ aa_overwalked (struct func_body_info *fbi)
+ {
+   gcc_checking_assert (fbi);
+   return fbi->aa_walked > (unsigned) PARAM_VALUE (PARAM_IPA_MAX_AA_STEPS);
+ }
+ 
+ /* Find the nearest valid aa status for parameter specified by INDEX that
+    dominates BB.  */
+ 
+ static struct param_aa_status *
+ find_dominating_aa_status (struct func_body_info *fbi, basic_block bb,
+ 			   int index)
+ {
+   while (true)
+     {
+       bb = get_immediate_dominator (CDI_DOMINATORS, bb);
+       if (!bb)
+ 	return NULL;
+       struct ipa_bb_info *bi = ipa_get_bb_info (fbi, bb);
+       if (!bi->paas.is_empty ()
+ 	  && bi->paas[index].valid)
+ 	return &bi->paas[index];
+     }
+ }
+ 
+ /* Get AA status structure for the given BB and parameter with INDEX.  Allocate
+    structures and/or intialize the result with a dominating description as
+    necessary.  */
+ 
+ static struct param_aa_status *
+ parm_bb_aa_status_for_bb (struct func_body_info *fbi, basic_block bb,
+ 			  int index)
+ {
+   gcc_checking_assert (fbi);
+   struct ipa_bb_info *bi = ipa_get_bb_info (fbi, bb);
+   if (bi->paas.is_empty ())
+     bi->paas.safe_grow_cleared (fbi->param_count);
+   struct param_aa_status *paa = &bi->paas[index];
+   if (!paa->valid)
+     {
+       gcc_checking_assert (!paa->parm_modified
+ 			   && !paa->ref_modified
+ 			   && !paa->pt_modified);
+       struct param_aa_status *dom_paa;
+       dom_paa = find_dominating_aa_status (fbi, bb, index);
+       if (dom_paa)
+ 	*paa = *dom_paa;
+       else
+ 	paa->valid = true;
+     }
+ 
+   return paa;
+ }
+ 
  /* Return true if a load from a formal parameter PARM_LOAD is known to retrieve
     a value known not to be modified in this function before reaching the
!    statement STMT.  FBI holds information about the function we have so far
!    gathered but do not survive the summary building stage.  */
  
  static bool
! parm_preserved_before_stmt_p (struct func_body_info *fbi, int index,
! 			      gimple stmt, tree parm_load)
  {
+   struct param_aa_status *paa;
    bool modified = false;
    ao_ref refd;
  
!   /* FIXME: FBI can be NULL if we are being called from outside
!      ipa_node_analysis or ipcp_transform_function, which currently happens
!      during inlining analysis.  It would be great to extend fbi's lifetime and
!      always have it.  Currently, we are just not afraid of too much walking in
!      that case.  */
!   if (fbi)
!     {
!       if (aa_overwalked (fbi))
! 	return false;
!       paa = parm_bb_aa_status_for_bb (fbi, gimple_bb (stmt), index);
!       if (paa->parm_modified)
! 	return false;
!     }
!   else
!     paa = NULL;
  
    gcc_checking_assert (gimple_vuse (stmt) != NULL_TREE);
    ao_ref_init (&refd, parm_load);
!   int walked = walk_aliased_vdefs (&refd, gimple_vuse (stmt), mark_modified,
! 				   &modified, NULL);
!   if (fbi)
!     fbi->aa_walked += walked;
!   if (paa && modified)
!     paa->parm_modified = true;
    return !modified;
  }
  
*************** parm_preserved_before_stmt_p (struct par
*** 805,812 ****
     modified.  Otherwise return -1.  */
  
  static int
! load_from_unmodified_param (vec<ipa_param_descriptor> descriptors,
! 			    struct param_analysis_info *parms_ainfo,
  			    gimple stmt)
  {
    int index;
--- 921,928 ----
     modified.  Otherwise return -1.  */
  
  static int
! load_from_unmodified_param (struct func_body_info *fbi,
! 			    vec<ipa_param_descriptor> descriptors,
  			    gimple stmt)
  {
    int index;
*************** load_from_unmodified_param (vec<ipa_para
*** 821,865 ****
  
    index = ipa_get_param_decl_index_1 (descriptors, op1);
    if (index < 0
!       || !parm_preserved_before_stmt_p (parms_ainfo ? &parms_ainfo[index]
! 					: NULL, stmt, op1))
      return -1;
  
    return index;
  }
  
! /* Return true if memory reference REF loads data that are known to be
!    unmodified in this function before reaching statement STMT.  PARM_AINFO, if
!    non-NULL, is a pointer to a structure containing temporary information about
!    PARM.  */
  
  static bool
! parm_ref_data_preserved_p (struct param_analysis_info *parm_ainfo,
! 			      gimple stmt, tree ref)
  {
    bool modified = false;
    ao_ref refd;
  
!   gcc_checking_assert (gimple_vuse (stmt));
!   if (parm_ainfo && parm_ainfo->ref_modified)
!     return false;
  
    ao_ref_init (&refd, ref);
!   walk_aliased_vdefs (&refd, gimple_vuse (stmt), mark_modified, &modified,
! 		      NULL);
!   if (parm_ainfo && modified)
!     parm_ainfo->ref_modified = true;
    return !modified;
  }
  
! /* Return true if the data pointed to by PARM is known to be unmodified in this
!    function before reaching call statement CALL into which it is passed.
!    PARM_AINFO is a pointer to a structure containing temporary information
!    about PARM.  */
  
  static bool
! parm_ref_data_pass_through_p (struct param_analysis_info *parm_ainfo,
! 			       gimple call, tree parm)
  {
    bool modified = false;
    ao_ref refd;
--- 937,995 ----
  
    index = ipa_get_param_decl_index_1 (descriptors, op1);
    if (index < 0
!       || !parm_preserved_before_stmt_p (fbi, index, stmt, op1))
      return -1;
  
    return index;
  }
  
! /* Return true if memory reference REF (which must be a load through parameter
!    with INDEX) loads data that are known to be unmodified in this function
!    before reaching statement STMT.  */
  
  static bool
! parm_ref_data_preserved_p (struct func_body_info *fbi,
! 			   int index, gimple stmt, tree ref)
  {
+   struct param_aa_status *paa;
    bool modified = false;
    ao_ref refd;
  
!   /* FIXME: FBI can be NULL if we are being called from outside
!      ipa_node_analysis or ipcp_transform_function, which currently happens
!      during inlining analysis.  It would be great to extend fbi's lifetime and
!      always have it.  Currently, we are just not afraid of too much walking in
!      that case.  */
!   if (fbi)
!     {
!       if (aa_overwalked (fbi))
! 	return false;
!       paa = parm_bb_aa_status_for_bb (fbi, gimple_bb (stmt), index);
!       if (paa->ref_modified)
! 	return false;
!     }
!   else
!     paa = NULL;
  
+   gcc_checking_assert (gimple_vuse (stmt));
    ao_ref_init (&refd, ref);
!   int walked = walk_aliased_vdefs (&refd, gimple_vuse (stmt), mark_modified,
! 				   &modified, NULL);
!   if (fbi)
!     fbi->aa_walked += walked;
!   if (paa && modified)
!     paa->ref_modified = true;
    return !modified;
  }
  
! /* Return true if the data pointed to by PARM (which is a parameter with INDEX)
!    is known to be unmodified in this function before reaching call statement
!    CALL into which it is passed.  PARM_AINFO is a pointer to a structure
!    containing temporary information about PARM.  */
  
  static bool
! parm_ref_data_pass_through_p (struct func_body_info *fbi, int index,
! 			      gimple call, tree parm)
  {
    bool modified = false;
    ao_ref refd;
*************** parm_ref_data_pass_through_p (struct par
*** 868,884 ****
       function because it is not goin to use it.  But do not cache the result
       either.  Also, no such calculations for non-pointers.  */
    if (!gimple_vuse (call)
!       || !POINTER_TYPE_P (TREE_TYPE (parm)))
      return false;
  
!   if (parm_ainfo->pt_modified)
      return false;
  
    ao_ref_init_from_ptr_and_size (&refd, parm, NULL_TREE);
!   walk_aliased_vdefs (&refd, gimple_vuse (call), mark_modified, &modified,
! 		      parm_ainfo ? &parm_ainfo->pt_visited_statements : NULL);
    if (modified)
!     parm_ainfo->pt_modified = true;
    return !modified;
  }
  
--- 998,1018 ----
       function because it is not goin to use it.  But do not cache the result
       either.  Also, no such calculations for non-pointers.  */
    if (!gimple_vuse (call)
!       || !POINTER_TYPE_P (TREE_TYPE (parm))
!       || aa_overwalked (fbi))
      return false;
  
!   struct param_aa_status *paa = parm_bb_aa_status_for_bb (fbi, gimple_bb (call),
! 							  index);
!   if (paa->pt_modified)
      return false;
  
    ao_ref_init_from_ptr_and_size (&refd, parm, NULL_TREE);
!   int walked = walk_aliased_vdefs (&refd, gimple_vuse (call), mark_modified,
! 				   &modified, NULL);
!   fbi->aa_walked += walked;
    if (modified)
!     paa->pt_modified = true;
    return !modified;
  }
  
*************** parm_ref_data_pass_through_p (struct par
*** 893,902 ****
     reference respectively.  */
  
  static bool
! ipa_load_from_parm_agg_1 (vec<ipa_param_descriptor> descriptors,
! 			  struct param_analysis_info *parms_ainfo, gimple stmt,
! 			  tree op, int *index_p, HOST_WIDE_INT *offset_p,
! 			  HOST_WIDE_INT *size_p, bool *by_ref_p)
  {
    int index;
    HOST_WIDE_INT size, max_size;
--- 1027,1037 ----
     reference respectively.  */
  
  static bool
! ipa_load_from_parm_agg_1 (struct func_body_info *fbi,
! 			  vec<ipa_param_descriptor> descriptors,
! 			  gimple stmt, tree op, int *index_p,
! 			  HOST_WIDE_INT *offset_p, HOST_WIDE_INT *size_p,
! 			  bool *by_ref_p)
  {
    int index;
    HOST_WIDE_INT size, max_size;
*************** ipa_load_from_parm_agg_1 (vec<ipa_param_
*** 909,916 ****
      {
        int index = ipa_get_param_decl_index_1 (descriptors, base);
        if (index >= 0
! 	  && parm_preserved_before_stmt_p (parms_ainfo ? &parms_ainfo[index]
! 					   : NULL, stmt, op))
  	{
  	  *index_p = index;
  	  *by_ref_p = false;
--- 1044,1050 ----
      {
        int index = ipa_get_param_decl_index_1 (descriptors, base);
        if (index >= 0
! 	  && parm_preserved_before_stmt_p (fbi, index, stmt, op))
  	{
  	  *index_p = index;
  	  *by_ref_p = false;
*************** ipa_load_from_parm_agg_1 (vec<ipa_param_
*** 949,960 ****
        */
  
        gimple def = SSA_NAME_DEF_STMT (TREE_OPERAND (base, 0));
!       index = load_from_unmodified_param (descriptors, parms_ainfo, def);
      }
  
    if (index >= 0
!       && parm_ref_data_preserved_p (parms_ainfo ? &parms_ainfo[index] : NULL,
! 				    stmt, op))
      {
        *index_p = index;
        *by_ref_p = true;
--- 1083,1093 ----
        */
  
        gimple def = SSA_NAME_DEF_STMT (TREE_OPERAND (base, 0));
!       index = load_from_unmodified_param (fbi, descriptors, def);
      }
  
    if (index >= 0
!       && parm_ref_data_preserved_p (fbi, index, stmt, op))
      {
        *index_p = index;
        *by_ref_p = true;
*************** ipa_load_from_parm_agg (struct ipa_node_
*** 973,979 ****
  			tree op, int *index_p, HOST_WIDE_INT *offset_p,
  			bool *by_ref_p)
  {
!   return ipa_load_from_parm_agg_1 (info->descriptors, NULL, stmt, op, index_p,
  				   offset_p, NULL, by_ref_p);
  }
  
--- 1106,1112 ----
  			tree op, int *index_p, HOST_WIDE_INT *offset_p,
  			bool *by_ref_p)
  {
!   return ipa_load_from_parm_agg_1 (NULL, info->descriptors, stmt, op, index_p,
  				   offset_p, NULL, by_ref_p);
  }
  
*************** ipa_load_from_parm_agg (struct ipa_node_
*** 1031,1038 ****
     only needed for intraprocedural analysis.  */
  
  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,
  				  tree param_type)
--- 1164,1171 ----
     only needed for intraprocedural analysis.  */
  
  static void
! compute_complex_assign_jump_func (struct func_body_info *fbi,
! 				  struct ipa_node_params *info,
  				  struct ipa_jump_func *jfunc,
  				  gimple call, gimple stmt, tree name,
  				  tree param_type)
*************** compute_complex_assign_jump_func (struct
*** 1048,1060 ****
        if (SSA_NAME_IS_DEFAULT_DEF (op1))
  	index = ipa_get_param_decl_index (info, SSA_NAME_VAR (op1));
        else
! 	index = load_from_unmodified_param (info->descriptors, parms_ainfo,
  					    SSA_NAME_DEF_STMT (op1));
        tc_ssa = op1;
      }
    else
      {
!       index = load_from_unmodified_param (info->descriptors, parms_ainfo, stmt);
        tc_ssa = gimple_assign_lhs (stmt);
      }
  
--- 1181,1193 ----
        if (SSA_NAME_IS_DEFAULT_DEF (op1))
  	index = ipa_get_param_decl_index (info, SSA_NAME_VAR (op1));
        else
! 	index = load_from_unmodified_param (fbi, info->descriptors,
  					    SSA_NAME_DEF_STMT (op1));
        tc_ssa = op1;
      }
    else
      {
!       index = load_from_unmodified_param (fbi, info->descriptors, stmt);
        tc_ssa = gimple_assign_lhs (stmt);
      }
  
*************** compute_complex_assign_jump_func (struct
*** 1075,1082 ****
  	}
        else if (gimple_assign_single_p (stmt))
  	{
! 	  bool agg_p = parm_ref_data_pass_through_p (&parms_ainfo[index],
! 						     call, tc_ssa);
  	  bool type_p = false;
  
  	  if (param_type && POINTER_TYPE_P (param_type))
--- 1208,1214 ----
  	}
        else if (gimple_assign_single_p (stmt))
  	{
! 	  bool agg_p = parm_ref_data_pass_through_p (fbi, index, call, tc_ssa);
  	  bool type_p = false;
  
  	  if (param_type && POINTER_TYPE_P (param_type))
*************** compute_complex_assign_jump_func (struct
*** 1115,1121 ****
        if (type_p || jfunc->type == IPA_JF_UNKNOWN)
  	ipa_set_ancestor_jf (jfunc, offset,
  			     type_p ? TREE_TYPE (param_type) : NULL, index,
! 			     parm_ref_data_pass_through_p (&parms_ainfo[index],
  							   call, ssa), type_p);
      }
  }
--- 1247,1253 ----
        if (type_p || jfunc->type == IPA_JF_UNKNOWN)
  	ipa_set_ancestor_jf (jfunc, offset,
  			     type_p ? TREE_TYPE (param_type) : NULL, index,
! 			     parm_ref_data_pass_through_p (fbi, index,
  							   call, ssa), type_p);
      }
  }
*************** get_ancestor_addr_info (gimple assign, t
*** 1187,1194 ****
       return D.1879_6;  */
  
  static void
! compute_complex_ancestor_jump_func (struct ipa_node_params *info,
! 				    struct param_analysis_info *parms_ainfo,
  				    struct ipa_jump_func *jfunc,
  				    gimple call, gimple phi, tree param_type)
  {
--- 1319,1326 ----
       return D.1879_6;  */
  
  static void
! compute_complex_ancestor_jump_func (struct func_body_info *fbi,
! 				    struct ipa_node_params *info,
  				    struct ipa_jump_func *jfunc,
  				    gimple call, gimple phi, tree param_type)
  {
*************** compute_complex_ancestor_jump_func (stru
*** 1247,1255 ****
      type_p = !detect_type_change (obj, expr, TREE_TYPE (param_type),
  				  call, jfunc, offset);
    if (type_p || jfunc->type == IPA_JF_UNKNOWN)
!     ipa_set_ancestor_jf (jfunc, offset, type_p ? TREE_TYPE (param_type) : NULL, index,
! 			 parm_ref_data_pass_through_p (&parms_ainfo[index],
! 						       call, parm), type_p);
  }
  
  /* Given OP which is passed as an actual argument to a called function,
--- 1379,1388 ----
      type_p = !detect_type_change (obj, expr, TREE_TYPE (param_type),
  				  call, jfunc, offset);
    if (type_p || jfunc->type == IPA_JF_UNKNOWN)
!     ipa_set_ancestor_jf (jfunc, offset, type_p ? TREE_TYPE (param_type) : NULL,
! 			 index,
! 			 parm_ref_data_pass_through_p (fbi, index, call, parm),
! 			 type_p);
  }
  
  /* Given OP which is passed as an actual argument to a called function,
*************** ipa_get_callee_param_type (struct cgraph
*** 1594,1600 ****
     to this callsite.  */
  
  static void
! 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);
--- 1727,1733 ----
     to this callsite.  */
  
  static void
! ipa_compute_jump_functions_for_edge (struct func_body_info *fbi,
  				     struct cgraph_edge *cs)
  {
    struct ipa_node_params *info = IPA_NODE_REF (cs->caller);
*************** ipa_compute_jump_functions_for_edge (str
*** 1628,1634 ****
  	  /* Aggregate passed by value, check for pass-through, otherwise we
  	     will attempt to fill in aggregate contents later in this
  	     for cycle.  */
! 	  if (parm_preserved_before_stmt_p (&parms_ainfo[index], call, arg))
  	    {
  	      ipa_set_jf_simple_pass_through (jfunc, index, false, false);
  	      continue;
--- 1761,1767 ----
  	  /* Aggregate passed by value, check for pass-through, otherwise we
  	     will attempt to fill in aggregate contents later in this
  	     for cycle.  */
! 	  if (parm_preserved_before_stmt_p (fbi, index, call, arg))
  	    {
  	      ipa_set_jf_simple_pass_through (jfunc, index, false, false);
  	      continue;
*************** ipa_compute_jump_functions_for_edge (str
*** 1642,1649 ****
  	      if (index >= 0)
  		{
  		  bool agg_p, type_p;
! 		  agg_p = parm_ref_data_pass_through_p (&parms_ainfo[index],
! 							call, arg);
  		  if (param_type && POINTER_TYPE_P (param_type))
  		    type_p = !detect_type_change_ssa (arg, TREE_TYPE (param_type),
  						      call, jfunc);
--- 1775,1781 ----
  	      if (index >= 0)
  		{
  		  bool agg_p, type_p;
! 		  agg_p = parm_ref_data_pass_through_p (fbi, index, call, arg);
  		  if (param_type && POINTER_TYPE_P (param_type))
  		    type_p = !detect_type_change_ssa (arg, TREE_TYPE (param_type),
  						      call, jfunc);
*************** ipa_compute_jump_functions_for_edge (str
*** 1658,1667 ****
  	    {
  	      gimple stmt = SSA_NAME_DEF_STMT (arg);
  	      if (is_gimple_assign (stmt))
! 		compute_complex_assign_jump_func (info, parms_ainfo, jfunc,
  						  call, stmt, arg, param_type);
  	      else if (gimple_code (stmt) == GIMPLE_PHI)
! 		compute_complex_ancestor_jump_func (info, parms_ainfo, jfunc,
  						    call, stmt, param_type);
  	    }
  	}
--- 1790,1799 ----
  	    {
  	      gimple stmt = SSA_NAME_DEF_STMT (arg);
  	      if (is_gimple_assign (stmt))
! 		compute_complex_assign_jump_func (fbi, info, jfunc,
  						  call, stmt, arg, param_type);
  	      else if (gimple_code (stmt) == GIMPLE_PHI)
! 		compute_complex_ancestor_jump_func (fbi, info, jfunc,
  						    call, stmt, param_type);
  	    }
  	}
*************** ipa_compute_jump_functions_for_edge (str
*** 1692,1718 ****
  }
  
  /* Compute jump functions for all edges - both direct and indirect - outgoing
!    from NODE.  Also count the actual arguments in the process.  */
  
  static void
! ipa_compute_jump_functions (struct cgraph_node *node,
! 			    struct param_analysis_info *parms_ainfo)
  {
    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.  */
!       if (!callee->definition && !flag_lto)
! 	continue;
!       ipa_compute_jump_functions_for_edge (parms_ainfo, cs);
!     }
  
!   for (cs = node->indirect_calls; cs; cs = cs->next_callee)
!     ipa_compute_jump_functions_for_edge (parms_ainfo, cs);
  }
  
  /* If STMT looks like a statement loading a value from a member pointer formal
--- 1824,1852 ----
  }
  
  /* Compute jump functions for all edges - both direct and indirect - outgoing
!    from BB.  */
  
  static void
! ipa_compute_jump_functions_for_bb (struct func_body_info *fbi, basic_block bb)
  {
+   struct ipa_bb_info *bi = ipa_get_bb_info (fbi, bb);
+   int i;
    struct cgraph_edge *cs;
  
!   FOR_EACH_VEC_ELT_REVERSE (bi->cg_edges, i, cs)
      {
!       struct cgraph_node *callee = cs->callee;
  
!       if (callee)
! 	{
! 	  cgraph_function_or_thunk_node (callee, NULL);
! 	  /* We do not need to bother analyzing calls to unknown functions
! 	     unless they may become known during lto/whopr.  */
! 	  if (!callee->definition && !flag_lto)
! 	    continue;
! 	}
!       ipa_compute_jump_functions_for_edge (fbi, cs);
!     }
  }
  
  /* If STMT looks like a statement loading a value from a member pointer formal
*************** ipa_note_param_call (struct cgraph_node
*** 1855,1891 ****
     passed by value or reference.  */
  
  static void
! ipa_analyze_indirect_call_uses (struct cgraph_node *node,
! 				struct ipa_node_params *info,
! 				struct param_analysis_info *parms_ainfo,
! 				gimple call, tree target)
! {
!   gimple def;
!   tree n1, n2;
!   gimple d1, d2;
!   tree rec, rec2, cond;
!   gimple branch;
!   int index;
!   basic_block bb, virt_bb, join;
    HOST_WIDE_INT offset;
    bool by_ref;
  
    if (SSA_NAME_IS_DEFAULT_DEF (target))
      {
        tree var = SSA_NAME_VAR (target);
!       index = ipa_get_param_decl_index (info, var);
        if (index >= 0)
! 	ipa_note_param_call (node, index, call);
        return;
      }
  
!   def = SSA_NAME_DEF_STMT (target);
    if (gimple_assign_single_p (def)
!       && ipa_load_from_parm_agg_1 (info->descriptors, parms_ainfo, def,
  				   gimple_assign_rhs1 (def), &index, &offset,
  				   NULL, &by_ref))
      {
!       struct cgraph_edge *cs = ipa_note_param_call (node, index, call);
        if (cs->indirect_info->offset != offset)
  	cs->indirect_info->outer_type = NULL;
        cs->indirect_info->offset = offset;
--- 1989,2018 ----
     passed by value or reference.  */
  
  static void
! ipa_analyze_indirect_call_uses (struct func_body_info *fbi, gimple call,
! 				tree target)
! {
!   struct ipa_node_params *info = fbi->info;
    HOST_WIDE_INT offset;
    bool by_ref;
  
    if (SSA_NAME_IS_DEFAULT_DEF (target))
      {
        tree var = SSA_NAME_VAR (target);
!       int index = ipa_get_param_decl_index (info, var);
        if (index >= 0)
! 	ipa_note_param_call (fbi->node, index, call);
        return;
      }
  
!   int index;
!   gimple def = SSA_NAME_DEF_STMT (target);
    if (gimple_assign_single_p (def)
!       && ipa_load_from_parm_agg_1 (fbi, info->descriptors, def,
  				   gimple_assign_rhs1 (def), &index, &offset,
  				   NULL, &by_ref))
      {
!       struct cgraph_edge *cs = ipa_note_param_call (fbi->node, index, call);
        if (cs->indirect_info->offset != offset)
  	cs->indirect_info->outer_type = NULL;
        cs->indirect_info->offset = offset;
*************** ipa_analyze_indirect_call_uses (struct c
*** 1904,1917 ****
  
    /* First, we need to check whether one of these is a load from a member
       pointer that is a parameter to this function. */
!   n1 = PHI_ARG_DEF (def, 0);
!   n2 = PHI_ARG_DEF (def, 1);
    if (!ipa_is_ssa_with_stmt_def (n1) || !ipa_is_ssa_with_stmt_def (n2))
      return;
!   d1 = SSA_NAME_DEF_STMT (n1);
!   d2 = SSA_NAME_DEF_STMT (n2);
  
!   join = gimple_bb (def);
    if ((rec = ipa_get_stmt_member_ptr_load_param (d1, false, &offset)))
      {
        if (ipa_get_stmt_member_ptr_load_param (d2, false, NULL))
--- 2031,2046 ----
  
    /* First, we need to check whether one of these is a load from a member
       pointer that is a parameter to this function. */
!   tree n1 = PHI_ARG_DEF (def, 0);
!   tree n2 = PHI_ARG_DEF (def, 1);
    if (!ipa_is_ssa_with_stmt_def (n1) || !ipa_is_ssa_with_stmt_def (n2))
      return;
!   gimple d1 = SSA_NAME_DEF_STMT (n1);
!   gimple d2 = SSA_NAME_DEF_STMT (n2);
  
!   tree rec;
!   basic_block bb, virt_bb;
!   basic_block join = gimple_bb (def);
    if ((rec = ipa_get_stmt_member_ptr_load_param (d1, false, &offset)))
      {
        if (ipa_get_stmt_member_ptr_load_param (d2, false, NULL))
*************** ipa_analyze_indirect_call_uses (struct c
*** 1939,1945 ****
    /* Third, let's see that the branching is done depending on the least
       significant bit of the pfn. */
  
!   branch = last_stmt (bb);
    if (!branch || gimple_code (branch) != GIMPLE_COND)
      return;
  
--- 2068,2074 ----
    /* Third, let's see that the branching is done depending on the least
       significant bit of the pfn. */
  
!   gimple branch = last_stmt (bb);
    if (!branch || gimple_code (branch) != GIMPLE_COND)
      return;
  
*************** ipa_analyze_indirect_call_uses (struct c
*** 1948,1954 ****
        || !integer_zerop (gimple_cond_rhs (branch)))
      return;
  
!   cond = gimple_cond_lhs (branch);
    if (!ipa_is_ssa_with_stmt_def (cond))
      return;
  
--- 2077,2083 ----
        || !integer_zerop (gimple_cond_rhs (branch)))
      return;
  
!   tree cond = gimple_cond_lhs (branch);
    if (!ipa_is_ssa_with_stmt_def (cond))
      return;
  
*************** ipa_analyze_indirect_call_uses (struct c
*** 1973,1978 ****
--- 2102,2108 ----
        def = SSA_NAME_DEF_STMT (cond);
      }
  
+   tree rec2;
    rec2 = ipa_get_stmt_member_ptr_load_param (def,
  					     (TARGET_PTRMEMFUNC_VBIT_LOCATION
  					      == ptrmemfunc_vbit_in_delta),
*************** ipa_analyze_indirect_call_uses (struct c
*** 1982,1990 ****
  
    index = ipa_get_param_decl_index (info, rec);
    if (index >= 0
!       && parm_preserved_before_stmt_p (&parms_ainfo[index], call, rec))
      {
!       struct cgraph_edge *cs = ipa_note_param_call (node, index, call);
        if (cs->indirect_info->offset != offset)
  	cs->indirect_info->outer_type = NULL;
        cs->indirect_info->offset = offset;
--- 2112,2120 ----
  
    index = ipa_get_param_decl_index (info, rec);
    if (index >= 0
!       && parm_preserved_before_stmt_p (fbi, index, call, rec))
      {
!       struct cgraph_edge *cs = ipa_note_param_call (fbi->node, index, call);
        if (cs->indirect_info->offset != offset)
  	cs->indirect_info->outer_type = NULL;
        cs->indirect_info->offset = offset;
*************** ipa_analyze_indirect_call_uses (struct c
*** 1997,2012 ****
  
  /* Analyze a CALL to an OBJ_TYPE_REF which is passed in TARGET and if the
     object referenced in the expression is a formal parameter of the caller
!    (described by INFO), create a call note for the statement. */
  
  static void
! ipa_analyze_virtual_call_uses (struct cgraph_node *node,
! 			       struct ipa_node_params *info, gimple call,
! 			       tree target)
  {
-   struct cgraph_edge *cs;
-   struct cgraph_indirect_call_info *ii;
-   struct ipa_jump_func jfunc;
    tree obj = OBJ_TYPE_REF_OBJECT (target);
    int index;
    HOST_WIDE_INT anc_offset;
--- 2127,2139 ----
  
  /* Analyze a CALL to an OBJ_TYPE_REF which is passed in TARGET and if the
     object referenced in the expression is a formal parameter of the caller
!    FBI->node (described by FBI->info), create a call note for the
!    statement.  */
  
  static void
! ipa_analyze_virtual_call_uses (struct func_body_info *fbi,
! 			       gimple call, tree target)
  {
    tree obj = OBJ_TYPE_REF_OBJECT (target);
    int index;
    HOST_WIDE_INT anc_offset;
*************** ipa_analyze_virtual_call_uses (struct cg
*** 2017,2024 ****
--- 2144,2153 ----
    if (TREE_CODE (obj) != SSA_NAME)
      return;
  
+   struct ipa_node_params *info = fbi->info;
    if (SSA_NAME_IS_DEFAULT_DEF (obj))
      {
+       struct ipa_jump_func jfunc;
        if (TREE_CODE (SSA_NAME_VAR (obj)) != PARM_DECL)
  	return;
  
*************** ipa_analyze_virtual_call_uses (struct cg
*** 2031,2036 ****
--- 2160,2166 ----
      }
    else
      {
+       struct ipa_jump_func jfunc;
        gimple stmt = SSA_NAME_DEF_STMT (obj);
        tree expr;
  
*************** ipa_analyze_virtual_call_uses (struct cg
*** 2045,2052 ****
  	return;
      }
  
!   cs = ipa_note_param_call (node, index, call);
!   ii = cs->indirect_info;
    ii->offset = anc_offset;
    ii->otr_token = tree_to_uhwi (OBJ_TYPE_REF_TOKEN (target));
    ii->otr_type = obj_type_ref_class (target);
--- 2175,2182 ----
  	return;
      }
  
!   struct cgraph_edge *cs = ipa_note_param_call (fbi->node, index, call);
!   struct cgraph_indirect_call_info *ii = cs->indirect_info;
    ii->offset = anc_offset;
    ii->otr_token = tree_to_uhwi (OBJ_TYPE_REF_TOKEN (target));
    ii->otr_type = obj_type_ref_class (target);
*************** ipa_analyze_virtual_call_uses (struct cg
*** 2058,2069 ****
     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_ainfo, gimple call)
  {
    tree target = gimple_call_fn (call);
-   struct cgraph_edge *cs;
  
    if (!target
        || (TREE_CODE (target) != SSA_NAME
--- 2188,2196 ----
     containing intermediate information about each formal parameter.  */
  
  static void
! ipa_analyze_call_uses (struct func_body_info *fbi, gimple call)
  {
    tree target = gimple_call_fn (call);
  
    if (!target
        || (TREE_CODE (target) != SSA_NAME
*************** ipa_analyze_call_uses (struct cgraph_nod
*** 2072,2098 ****
  
    /* If we previously turned the call into a direct call, there is
       no need to analyze.  */
!   cs = cgraph_edge (node, call);
    if (cs && !cs->indirect_unknown_callee)
      return;
    if (TREE_CODE (target) == SSA_NAME)
!     ipa_analyze_indirect_call_uses (node, info, parms_ainfo, call, target);
    else if (virtual_method_call_p (target))
!     ipa_analyze_virtual_call_uses (node, info, call, target);
  }
  
  
  /* 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_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,
! 		       struct param_analysis_info *parms_ainfo, gimple stmt)
  {
    if (is_gimple_call (stmt))
!     ipa_analyze_call_uses (node, info, parms_ainfo, stmt);
  }
  
  /* Callback of walk_stmt_load_store_addr_ops for the visit_load.
--- 2199,2223 ----
  
    /* If we previously turned the call into a direct call, there is
       no need to analyze.  */
!   struct cgraph_edge *cs = cgraph_edge (fbi->node, call);
    if (cs && !cs->indirect_unknown_callee)
      return;
    if (TREE_CODE (target) == SSA_NAME)
!     ipa_analyze_indirect_call_uses (fbi, call, target);
    else if (virtual_method_call_p (target))
!     ipa_analyze_virtual_call_uses (fbi, call, target);
  }
  
  
  /* Analyze the call statement STMT with respect to formal parameters (described
!    in INFO) of caller given by FBI->NODE.  Currently it only checks whether
!    formal parameters are called.  */
  
  static void
! ipa_analyze_stmt_uses (struct func_body_info *fbi, gimple stmt)
  {
    if (is_gimple_call (stmt))
!     ipa_analyze_call_uses (fbi, stmt);
  }
  
  /* Callback of walk_stmt_load_store_addr_ops for the visit_load.
*************** visit_ref_for_mod_analysis (gimple, tree
*** 2116,2152 ****
    return false;
  }
  
! /* 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_AINFO is a pointer to a
!    vector containing intermediate information about each formal parameter.   */
  
  static void
! ipa_analyze_params_uses (struct cgraph_node *node,
! 			 struct param_analysis_info *parms_ainfo)
  {
-   tree decl = node->decl;
-   basic_block bb;
-   struct function *func;
    gimple_stmt_iterator gsi;
!   struct ipa_node_params *info = IPA_NODE_REF (node);
!   int i;
  
!   if (ipa_get_param_count (info) == 0 || info->uses_analysis_done)
!     return;
  
!   info->uses_analysis_done = 1;
!   if (ipa_func_spec_opts_forbid_analysis_p (node))
!     {
!       for (i = 0; i < ipa_get_param_count (info); i++)
! 	{
! 	  ipa_set_param_used (info, i, true);
! 	  ipa_set_controlled_uses (info, i, IPA_UNDESCRIBED_USE);
! 	}
!       return;
!     }
  
!   for (i = 0; i < ipa_get_param_count (info); i++)
      {
        tree parm = ipa_get_param (info, i);
        int controlled_uses = 0;
--- 2241,2283 ----
    return false;
  }
  
! /* Scan the statements in BB 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.  FBI holds various data about
!    the function being analyzed.  */
  
  static void
! ipa_analyze_params_uses_in_bb (struct func_body_info *fbi, basic_block bb)
  {
    gimple_stmt_iterator gsi;
!   for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
!     {
!       gimple stmt = gsi_stmt (gsi);
  
!       if (is_gimple_debug (stmt))
! 	continue;
  
!       ipa_analyze_stmt_uses (fbi, stmt);
!       walk_stmt_load_store_addr_ops (stmt, fbi->info,
! 				     visit_ref_for_mod_analysis,
! 				     visit_ref_for_mod_analysis,
! 				     visit_ref_for_mod_analysis);
!     }
!   for (gsi = gsi_start_phis (bb); !gsi_end_p (gsi); gsi_next (&gsi))
!     walk_stmt_load_store_addr_ops (gsi_stmt (gsi), fbi->info,
! 				   visit_ref_for_mod_analysis,
! 				   visit_ref_for_mod_analysis,
! 				   visit_ref_for_mod_analysis);
! }
! 
! /* Calculate controlled uses of parameters of NODE.  */
! 
! static void
! ipa_analyze_controlled_uses (struct cgraph_node *node)
! {
!   struct ipa_node_params *info = IPA_NODE_REF (node);
  
!   for (int i = 0; i < ipa_get_param_count (info); i++)
      {
        tree parm = ipa_get_param (info, i);
        int controlled_uses = 0;
*************** ipa_analyze_params_uses (struct cgraph_n
*** 2182,2226 ****
  	controlled_uses = IPA_UNDESCRIBED_USE;
        ipa_set_controlled_uses (info, i, controlled_uses);
      }
  
!   func = DECL_STRUCT_FUNCTION (decl);
!   FOR_EACH_BB_FN (bb, func)
!     {
!       for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
! 	{
! 	  gimple stmt = gsi_stmt (gsi);
! 
! 	  if (is_gimple_debug (stmt))
! 	    continue;
  
! 	  ipa_analyze_stmt_uses (node, info, parms_ainfo, stmt);
! 	  walk_stmt_load_store_addr_ops (stmt, info,
! 					 visit_ref_for_mod_analysis,
! 					 visit_ref_for_mod_analysis,
! 					 visit_ref_for_mod_analysis);
! 	}
!       for (gsi = gsi_start_phis (bb); !gsi_end_p (gsi); gsi_next (&gsi))
! 	walk_stmt_load_store_addr_ops (gsi_stmt (gsi), info,
! 				       visit_ref_for_mod_analysis,
! 				       visit_ref_for_mod_analysis,
! 				       visit_ref_for_mod_analysis);
!     }
  }
  
! /* Free stuff in PARMS_AINFO, assume there are PARAM_COUNT parameters.  */
  
! static void
! free_parms_ainfo (struct param_analysis_info *parms_ainfo, int param_count)
  {
!   int i;
  
!   for (i = 0; i < param_count; i++)
!     {
!       if (parms_ainfo[i].parm_visited_statements)
! 	BITMAP_FREE (parms_ainfo[i].parm_visited_statements);
!       if (parms_ainfo[i].pt_visited_statements)
! 	BITMAP_FREE (parms_ainfo[i].pt_visited_statements);
!     }
  }
  
  /* Initialize the array describing properties of of formal parameters
--- 2313,2348 ----
  	controlled_uses = IPA_UNDESCRIBED_USE;
        ipa_set_controlled_uses (info, i, controlled_uses);
      }
+ }
  
! /* Free stuff in BI.  */
  
! static void
! free_ipa_bb_info (struct ipa_bb_info *bi)
! {
!   bi->cg_edges.release ();
!   bi->paas.release ();
  }
  
! /* Dominator walker driving the analysis.  */
  
! class analysis_dom_walker : public dom_walker
  {
! public:
!   analysis_dom_walker (struct func_body_info *fbi)
!     : dom_walker (CDI_DOMINATORS), m_fbi (fbi) {}
  
!   virtual void before_dom_children (basic_block);
! 
! private:
!   struct func_body_info *m_fbi;
! };
! 
! void
! analysis_dom_walker::before_dom_children (basic_block bb)
! {
!   ipa_analyze_params_uses_in_bb (m_fbi, bb);
!   ipa_compute_jump_functions_for_bb (m_fbi, bb);
  }
  
  /* Initialize the array describing properties of of formal parameters
*************** free_parms_ainfo (struct param_analysis_
*** 2230,2253 ****
  void
  ipa_analyze_node (struct cgraph_node *node)
  {
    struct ipa_node_params *info;
-   struct param_analysis_info *parms_ainfo;
-   int param_count;
  
    ipa_check_create_node_params ();
    ipa_check_create_edge_args ();
    info = IPA_NODE_REF (node);
!   push_cfun (DECL_STRUCT_FUNCTION (node->decl));
    ipa_initialize_node_params (node);
  
!   param_count = ipa_get_param_count (info);
!   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_ainfo);
!   ipa_compute_jump_functions (node, parms_ainfo);
  
!   free_parms_ainfo (parms_ainfo, param_count);
    pop_cfun ();
  }
  
--- 2352,2411 ----
  void
  ipa_analyze_node (struct cgraph_node *node)
  {
+   struct func_body_info fbi;
    struct ipa_node_params *info;
  
    ipa_check_create_node_params ();
    ipa_check_create_edge_args ();
    info = IPA_NODE_REF (node);
! 
!   if (info->analysis_done)
!     return;
!   info->analysis_done = 1;
! 
!   if (ipa_func_spec_opts_forbid_analysis_p (node))
!     {
!       for (int i = 0; i < ipa_get_param_count (info); i++)
! 	{
! 	  ipa_set_param_used (info, i, true);
! 	  ipa_set_controlled_uses (info, i, IPA_UNDESCRIBED_USE);
! 	}
!       return;
!     }
! 
!   struct function *func = DECL_STRUCT_FUNCTION (node->decl);
!   push_cfun (func);
!   calculate_dominance_info (CDI_DOMINATORS);
    ipa_initialize_node_params (node);
+   ipa_analyze_controlled_uses (node);
  
!   fbi.node = node;
!   fbi.info = IPA_NODE_REF (node);
!   fbi.ibbis = vNULL;
!   fbi.ibbis.safe_grow_cleared (last_basic_block_for_fn (cfun));
!   fbi.param_count = ipa_get_param_count (info);
!   fbi.aa_walked = 0;
  
!   for (struct cgraph_edge *cs = node->callees; cs; cs = cs->next_callee)
!     {
!       ipa_bb_info *bi = ipa_get_bb_info (&fbi, gimple_bb (cs->call_stmt));
!       bi->cg_edges.safe_push (cs);
!     }
  
!   for (struct cgraph_edge *cs = node->indirect_calls; cs; cs = cs->next_callee)
!     {
!       ipa_bb_info *bi = ipa_get_bb_info (&fbi, gimple_bb (cs->call_stmt));
!       bi->cg_edges.safe_push (cs);
!     }
! 
!   analysis_dom_walker (&fbi).walk (ENTRY_BLOCK_PTR_FOR_FN (cfun));
! 
!   int i;
!   struct ipa_bb_info *bi;
!   FOR_EACH_VEC_ELT (fbi.ibbis, i, bi)
!     free_ipa_bb_info (bi);
!   fbi.ibbis.release ();
!   free_dominance_info (CDI_DOMINATORS);
    pop_cfun ();
  }
  
*************** ipa_node_duplication_hook (struct cgraph
*** 3299,3305 ****
    new_info->lattices = NULL;
    new_info->ipcp_orig_node = old_info->ipcp_orig_node;
  
!   new_info->uses_analysis_done = old_info->uses_analysis_done;
    new_info->node_enqueued = old_info->node_enqueued;
  
    old_av = ipa_get_agg_replacements_for_node (src);
--- 3457,3463 ----
    new_info->lattices = NULL;
    new_info->ipcp_orig_node = old_info->ipcp_orig_node;
  
!   new_info->analysis_done = old_info->analysis_done;
    new_info->node_enqueued = old_info->node_enqueued;
  
    old_av = ipa_get_agg_replacements_for_node (src);
*************** ipa_write_node_info (struct output_block
*** 4424,4430 ****
    for (j = 0; j < ipa_get_param_count (info); j++)
      streamer_write_uhwi (ob, ipa_get_param_move_cost (info, j));
    bp = bitpack_create (ob->main_stream);
!   gcc_assert (info->uses_analysis_done
  	      || ipa_get_param_count (info) == 0);
    gcc_assert (!info->node_enqueued);
    gcc_assert (!info->ipcp_orig_node);
--- 4582,4588 ----
    for (j = 0; j < ipa_get_param_count (info); j++)
      streamer_write_uhwi (ob, ipa_get_param_move_cost (info, j));
    bp = bitpack_create (ob->main_stream);
!   gcc_assert (info->analysis_done
  	      || ipa_get_param_count (info) == 0);
    gcc_assert (!info->node_enqueued);
    gcc_assert (!info->ipcp_orig_node);
*************** ipa_read_node_info (struct lto_input_blo
*** 4470,4476 ****
      
    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++)
      ipa_set_param_used (info, k, bp_unpack_value (&bp, 1));
--- 4628,4634 ----
      
    bp = streamer_read_bitpack (ib);
    if (ipa_get_param_count (info) != 0)
!     info->analysis_done = true;
    info->node_enqueued = false;
    for (k = 0; k < ipa_get_param_count (info); k++)
      ipa_set_param_used (info, k, bp_unpack_value (&bp, 1));
*************** adjust_agg_replacement_values (struct cg
*** 4820,4836 ****
      v->index = adj[v->index];
  }
  
  
! /* Function body transformation phase.  */
  
  unsigned int
  ipcp_transform_function (struct cgraph_node *node)
  {
    vec<ipa_param_descriptor> descriptors = vNULL;
!   struct param_analysis_info *parms_ainfo;
    struct ipa_agg_replacement_value *aggval;
-   gimple_stmt_iterator gsi;
-   basic_block bb;
    int param_count;
    bool cfg_changed = false, something_changed = false;
  
--- 4978,5106 ----
      v->index = adj[v->index];
  }
  
+ /* Dominator walker driving the ipcp modification phase.  */
+ 
+ class ipcp_modif_dom_walker : public dom_walker
+ {
+ public:
+   ipcp_modif_dom_walker (struct func_body_info *fbi,
+ 			 vec<ipa_param_descriptor> descs,
+ 			 struct ipa_agg_replacement_value *av,
+ 			 bool *sc, bool *cc)
+     : dom_walker (CDI_DOMINATORS), m_fbi (fbi), m_descriptors (descs),
+       m_aggval (av), m_something_changed (sc), m_cfg_changed (cc) {}
+ 
+   virtual void before_dom_children (basic_block);
+ 
+ private:
+   struct func_body_info *m_fbi;
+   vec<ipa_param_descriptor> m_descriptors;
+   struct ipa_agg_replacement_value *m_aggval;
+   bool *m_something_changed, *m_cfg_changed;
+ };
+ 
+ void
+ ipcp_modif_dom_walker::before_dom_children (basic_block bb)
+ {
+   gimple_stmt_iterator gsi;
+   for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
+     {
+       struct ipa_agg_replacement_value *v;
+       gimple stmt = gsi_stmt (gsi);
+       tree rhs, val, t;
+       HOST_WIDE_INT offset, size;
+       int index;
+       bool by_ref, vce;
+ 
+       if (!gimple_assign_load_p (stmt))
+ 	continue;
+       rhs = gimple_assign_rhs1 (stmt);
+       if (!is_gimple_reg_type (TREE_TYPE (rhs)))
+ 	continue;
  
!       vce = false;
!       t = rhs;
!       while (handled_component_p (t))
! 	{
! 	  /* V_C_E can do things like convert an array of integers to one
! 	     bigger integer and similar things we do not handle below.  */
! 	  if (TREE_CODE (rhs) == VIEW_CONVERT_EXPR)
! 	    {
! 	      vce = true;
! 	      break;
! 	    }
! 	  t = TREE_OPERAND (t, 0);
! 	}
!       if (vce)
! 	continue;
! 
!       if (!ipa_load_from_parm_agg_1 (m_fbi, m_descriptors, stmt, rhs, &index,
! 				     &offset, &size, &by_ref))
! 	continue;
!       for (v = m_aggval; v; v = v->next)
! 	if (v->index == index
! 	    && v->offset == offset)
! 	  break;
!       if (!v
! 	  || v->by_ref != by_ref
! 	  || tree_to_shwi (TYPE_SIZE (TREE_TYPE (v->value))) != size)
! 	continue;
! 
!       gcc_checking_assert (is_gimple_ip_invariant (v->value));
!       if (!useless_type_conversion_p (TREE_TYPE (rhs), TREE_TYPE (v->value)))
! 	{
! 	  if (fold_convertible_p (TREE_TYPE (rhs), v->value))
! 	    val = fold_build1 (NOP_EXPR, TREE_TYPE (rhs), v->value);
! 	  else if (TYPE_SIZE (TREE_TYPE (rhs))
! 		   == TYPE_SIZE (TREE_TYPE (v->value)))
! 	    val = fold_build1 (VIEW_CONVERT_EXPR, TREE_TYPE (rhs), v->value);
! 	  else
! 	    {
! 	      if (dump_file)
! 		{
! 		  fprintf (dump_file, "    const ");
! 		  print_generic_expr (dump_file, v->value, 0);
! 		  fprintf (dump_file, "  can't be converted to type of ");
! 		  print_generic_expr (dump_file, rhs, 0);
! 		  fprintf (dump_file, "\n");
! 		}
! 	      continue;
! 	    }
! 	}
!       else
! 	val = v->value;
! 
!       if (dump_file && (dump_flags & TDF_DETAILS))
! 	{
! 	  fprintf (dump_file, "Modifying stmt:\n  ");
! 	  print_gimple_stmt (dump_file, stmt, 0, 0);
! 	}
!       gimple_assign_set_rhs_from_tree (&gsi, val);
!       update_stmt (stmt);
! 
!       if (dump_file && (dump_flags & TDF_DETAILS))
! 	{
! 	  fprintf (dump_file, "into:\n  ");
! 	  print_gimple_stmt (dump_file, stmt, 0, 0);
! 	  fprintf (dump_file, "\n");
! 	}
! 
!       *m_something_changed = true;
!       if (maybe_clean_eh_stmt (stmt)
! 	  && gimple_purge_dead_eh_edges (gimple_bb (stmt)))
! 	*m_cfg_changed = true;
!     }
! 
! }
! 
! /* IPCP transformation phase doing propagation of aggregate values.  */
  
  unsigned int
  ipcp_transform_function (struct cgraph_node *node)
  {
    vec<ipa_param_descriptor> descriptors = vNULL;
!   struct func_body_info fbi;
    struct ipa_agg_replacement_value *aggval;
    int param_count;
    bool cfg_changed = false, something_changed = false;
  
*************** ipcp_transform_function (struct cgraph_n
*** 4850,4951 ****
    adjust_agg_replacement_values (node, aggval);
    if (dump_file)
      ipa_dump_agg_replacement_values (dump_file, aggval);
-   parms_ainfo = XALLOCAVEC (struct param_analysis_info, param_count);
-   memset (parms_ainfo, 0, sizeof (struct param_analysis_info) * param_count);
-   descriptors.safe_grow_cleared (param_count);
-   ipa_populate_param_decls (node, descriptors);
- 
-   FOR_EACH_BB_FN (bb, cfun)
-     for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
-       {
- 	struct ipa_agg_replacement_value *v;
- 	gimple stmt = gsi_stmt (gsi);
- 	tree rhs, val, t;
- 	HOST_WIDE_INT offset, size;
- 	int index;
- 	bool by_ref, vce;
- 
- 	if (!gimple_assign_load_p (stmt))
- 	  continue;
- 	rhs = gimple_assign_rhs1 (stmt);
- 	if (!is_gimple_reg_type (TREE_TYPE (rhs)))
- 	  continue;
- 
- 	vce = false;
- 	t = rhs;
- 	while (handled_component_p (t))
- 	  {
- 	    /* V_C_E can do things like convert an array of integers to one
-                bigger integer and similar things we do not handle below.  */
-             if (TREE_CODE (rhs) == VIEW_CONVERT_EXPR)
- 	      {
- 		vce = true;
- 		break;
- 	      }
- 	    t = TREE_OPERAND (t, 0);
- 	  }
- 	if (vce)
- 	  continue;
  
! 	if (!ipa_load_from_parm_agg_1 (descriptors, parms_ainfo, stmt,
! 				       rhs, &index, &offset, &size, &by_ref))
! 	  continue;
! 	for (v = aggval; v; v = v->next)
! 	  if (v->index == index
! 	      && v->offset == offset)
! 	    break;
! 	if (!v
! 	    || v->by_ref != by_ref
! 	    || tree_to_shwi (TYPE_SIZE (TREE_TYPE (v->value))) != size)
! 	  continue;
  
! 	gcc_checking_assert (is_gimple_ip_invariant (v->value));
! 	if (!useless_type_conversion_p (TREE_TYPE (rhs), TREE_TYPE (v->value)))
! 	  {
! 	    if (fold_convertible_p (TREE_TYPE (rhs), v->value))
! 	      val = fold_build1 (NOP_EXPR, TREE_TYPE (rhs), v->value);
! 	    else if (TYPE_SIZE (TREE_TYPE (rhs))
! 		     == TYPE_SIZE (TREE_TYPE (v->value)))
! 	      val = fold_build1 (VIEW_CONVERT_EXPR, TREE_TYPE (rhs), v->value);
! 	    else
! 	      {
! 		if (dump_file)
! 		  {
! 		    fprintf (dump_file, "    const ");
! 		    print_generic_expr (dump_file, v->value, 0);
! 		    fprintf (dump_file, "  can't be converted to type of ");
! 		    print_generic_expr (dump_file, rhs, 0);
! 		    fprintf (dump_file, "\n");
! 		  }
! 		continue;
! 	      }
! 	  }
! 	else
! 	  val = v->value;
! 
! 	if (dump_file && (dump_flags & TDF_DETAILS))
! 	  {
! 	    fprintf (dump_file, "Modifying stmt:\n  ");
! 	    print_gimple_stmt (dump_file, stmt, 0, 0);
! 	  }
! 	gimple_assign_set_rhs_from_tree (&gsi, val);
! 	update_stmt (stmt);
! 
! 	if (dump_file && (dump_flags & TDF_DETAILS))
! 	  {
! 	    fprintf (dump_file, "into:\n  ");
! 	    print_gimple_stmt (dump_file, stmt, 0, 0);
! 	    fprintf (dump_file, "\n");
! 	  }
! 
! 	something_changed = true;
! 	if (maybe_clean_eh_stmt (stmt)
! 	    && gimple_purge_dead_eh_edges (gimple_bb (stmt)))
! 	  cfg_changed = true;
!       }
  
    (*ipa_node_agg_replacements)[node->uid] = NULL;
-   free_parms_ainfo (parms_ainfo, param_count);
    descriptors.release ();
  
    if (!something_changed)
--- 5120,5146 ----
    adjust_agg_replacement_values (node, aggval);
    if (dump_file)
      ipa_dump_agg_replacement_values (dump_file, aggval);
  
!   fbi.node = node;
!   fbi.info = NULL;
!   fbi.ibbis = vNULL;
!   fbi.ibbis.safe_grow_cleared (last_basic_block_for_fn (cfun));
!   fbi.param_count = param_count;
!   fbi.aa_walked = 0;
  
!   descriptors.safe_grow_cleared (param_count);
!   ipa_populate_param_decls (node, descriptors);
!   calculate_dominance_info (CDI_DOMINATORS);
!   ipcp_modif_dom_walker (&fbi, descriptors, aggval, &something_changed,
! 			 &cfg_changed).walk (ENTRY_BLOCK_PTR_FOR_FN (cfun));
  
+   int i;
+   struct ipa_bb_info *bi;
+   FOR_EACH_VEC_ELT (fbi.ibbis, i, bi)
+     free_ipa_bb_info (bi);
+   fbi.ibbis.release ();
+   free_dominance_info (CDI_DOMINATORS);
    (*ipa_node_agg_replacements)[node->uid] = NULL;
    descriptors.release ();
  
    if (!something_changed)
Index: src/gcc/ipa-prop.h
===================================================================
*** src.orig/gcc/ipa-prop.h
--- src/gcc/ipa-prop.h
*************** struct ipa_node_params
*** 371,378 ****
    /* If this node is an ipa-cp clone, these are the known values that describe
       what it has been specialized for.  */
    vec<tree> known_vals;
!   /* Whether the param uses analysis has already been performed.  */
!   unsigned uses_analysis_done : 1;
    /* Whether the function is enqueued in ipa-cp propagation stack.  */
    unsigned node_enqueued : 1;
    /* Whether we should create a specialized version based on values that are
--- 371,379 ----
    /* If this node is an ipa-cp clone, these are the known values that describe
       what it has been specialized for.  */
    vec<tree> known_vals;
!   /* Whether the param uses analysis and jump function computation has already
!      been performed.  */
!   unsigned analysis_done : 1;
    /* Whether the function is enqueued in ipa-cp propagation stack.  */
    unsigned node_enqueued : 1;
    /* Whether we should create a specialized version based on values that are
Index: src/gcc/params.def
===================================================================
*** src.orig/gcc/params.def
--- src/gcc/params.def
*************** DEFPARAM (PARAM_IPA_MAX_AGG_ITEMS,
*** 947,952 ****
--- 947,958 ----
  	  "jump functions and lattices",
  	  16, 0, 0)
  
+ DEFPARAM (PARAM_IPA_MAX_AA_STEPS,
+ 	  "ipa-max-aa-steps",
+ 	  "Maximum number of statements that will be visited by IPA formal "
+ 	  "parameter analysis based on alias analysis in any given function",
+ 	  100000, 0, 0)
+ 
  DEFPARAM (PARAM_IPA_CP_LOOP_HINT_BONUS,
  	  "ipa-cp-loop-hint-bonus",
  	  "Compile-time bonus IPA-CP assigns to candidates which make loop "

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH] Make ipa-prop analyze BBs in DOM order
  2014-04-25 15:30 [PATCH] Make ipa-prop analyze BBs in DOM order Martin Jambor
@ 2014-04-28  9:05 ` Richard Biener
  2014-04-28 10:06   ` Martin Jambor
  2014-05-15 18:42 ` Jan Hubicka
  1 sibling, 1 reply; 5+ messages in thread
From: Richard Biener @ 2014-04-28  9:05 UTC (permalink / raw)
  To: GCC Patches, Jan Hubicka

On Fri, Apr 25, 2014 at 5:12 PM, Martin Jambor <mjambor@suse.cz> wrote:
> Hi,
>
> the following patch deals with requested propagation in PR 53787 in
> the real benchmark (as opposed to the original simple testcase) by
> analyzing individual BBs in ipa-prop.c in dominator order.
>
> Currently we do the analysis in two loops, in the first the order is
> given by FOR_EACH_BB_FN and in the second the order is the order of
> call graph edges (which in practice is quite bad because we tend to
> start with BBs towards the end).  When analysis determines that a
> non-SSA parameter or that data pointed to by a parameter are modified,
> this is marked into a function wide flag (describing the parameter)
> and we always consider the data clobbered from that moment on in order
> to save AA walking.
>
> This patch changes the analysis into dominator order and data is
> considered clobbered only in dominator children of a block where it
> was determined to be possibly clobbered, not in the whole function.
> This was confirmed to help in the aforementioned PR.
>
> The patch also, enforces a cap on the number of statements walked
> (approx. 4 times the highest I have ever seen).  On the other hand it
> gives up trying to cache the bitmap of visited memory-SSAs.  The
> per-BB information had to be put somewhere and I took this opportunity
> to cram a lot of commonly used per-function data into the same
> structure, which is then passed among various functions.  The new
> structure replaces the struct param_analysis_info.
>
> Bootstrapped and tested on x86_64-linux, I have also LTO-built Firefox
> at -O3 with it.  OK for trunk?

100000 is a very big number - is that a count for the whole program?
Did you make sure to excercise the fallback path by for example
bootstrapping or building firefox with a much lower number (say, 1)?

Walking all immediate dominators as fallback possibly visits
on the order of O (n_basic_blocks) blocks, so it isn't really "fast".
It's surely faster than doing the oracle walk, but can't we have a
quicker fallback (like fail?)

Thanks,
Richard.

> Thanks,
>
> Martin
>
>
> 2014-02-12  Martin Jambor  <mjambor@suse.cz>
>
>         PR tree-optimization/53787
>         * params.def (PARAM_IPA_CP_LOOP_HINT_BONUS): New param.
>         * ipa-prop.h (ipa_node_params): Rename uses_analysis_done to
>         analysis_done, update all uses.
>         * ipa-prop.c: Include domwalk.h
>         (param_analysis_info): Removed.
>         (param_aa_status): New type.
>         (ipa_bb_info): Likewise.
>         (func_body_info): Likewise.
>         (ipa_get_bb_info): New function.
>         (aa_overwalked): Likewise.
>         (find_dominating_aa_status): Likewise.
>         (parm_bb_aa_status_for_bb): Likewise.
>         (parm_preserved_before_stmt_p): Changed to use new param AA info.
>         (load_from_unmodified_param): Accept func_body_info as a parameter
>         instead of parms_ainfo.
>         (parm_ref_data_preserved_p): Changed to use new param AA info.
>         (parm_ref_data_pass_through_p): Likewise.
>         (ipa_load_from_parm_agg_1): Likewise.  Update callers.
>         (compute_complex_assign_jump_func): Changed to use new param AA info.
>         (compute_complex_ancestor_jump_func): Likewise.
>         (ipa_compute_jump_functions_for_edge): Likewise.
>         (ipa_compute_jump_functions): Removed.
>         (ipa_compute_jump_functions_for_bb): New function.
>         (ipa_analyze_indirect_call_uses): Likewise, moved variable
>         declarations down.
>         (ipa_analyze_virtual_call_uses): Accept func_body_info instead of node
>         and info, moved variable declarations down.
>         (ipa_analyze_call_uses): Accept and pass on func_body_info instead of
>         node and info.
>         (ipa_analyze_stmt_uses): Likewise.
>         (ipa_analyze_params_uses): Removed.
>         (ipa_analyze_params_uses_in_bb): New function.
>         (ipa_analyze_controlled_uses): Likewise.
>         (free_ipa_bb_info): Likewise.
>         (analysis_dom_walker): New class.
>         (ipa_analyze_node): Handle node-specific forbidden analysis,
>         initialize and free func_body_info, use dominator walker.
>         (ipcp_modif_dom_walker): New class.
>         (ipcp_transform_function): Create and free func_body_info, use
>         ipcp_modif_dom_walker, moved a lot of functionality there.
>
> Index: src/gcc/ipa-prop.c
> ===================================================================
> *** src.orig/gcc/ipa-prop.c
> --- src/gcc/ipa-prop.c
> *************** along with GCC; see the file COPYING3.
> *** 59,72 ****
>   #include "ipa-utils.h"
>   #include "stringpool.h"
>   #include "tree-ssanames.h"
>
> ! /* Intermediate information about a parameter that is only useful during the
> !    run of ipa_analyze_node and is not kept afterwards.  */
>
> ! struct param_analysis_info
>   {
>     bool parm_modified, ref_modified, pt_modified;
> !   bitmap parm_visited_statements, pt_visited_statements;
>   };
>
>   /* Vector where the parameter infos are actually stored. */
> --- 59,111 ----
>   #include "ipa-utils.h"
>   #include "stringpool.h"
>   #include "tree-ssanames.h"
> + #include "domwalk.h"
>
> ! /* Intermediate information that we get from AA analysis about a parameter.  */
>
> ! struct param_aa_status
>   {
> +   /* If not true, look at the dominator parent instead.  */
> +   bool valid;
> +
> +   /* Whether we have seen something which might have modified the data in
> +      question.  Parm is for the parameter itself, ref is for data it points to
> +      but using the alias type of individual accesses and pt is the same thing
> +      but for computing aggregate pass-through functions using a very inclusive
> +      ao_ref.  */
>     bool parm_modified, ref_modified, pt_modified;
> ! };
> !
> ! /* Information related to a given BB that used only when looking at function
> !    body.  */
> !
> ! struct ipa_bb_info
> ! {
> !   /* Call graph edges going out of this BB.  */
> !   vec<cgraph_edge_p> cg_edges;
> !   /* Alias analysis statuses of each formal parameter at this bb.  */
> !   vec<param_aa_status> paas;
> ! };
> !
> ! /* Structure with global information that is only used when looking at function
> !    body. */
> !
> ! struct func_body_info
> ! {
> !   /* The node that is being analyzed.  */
> !   cgraph_node *node;
> !
> !   /* Its info.  */
> !   struct ipa_node_params *info;
> !
> !   /* Information about individual BBs. */
> !   vec<ipa_bb_info> ibbis;
> !
> !   /* Number of parameters.  */
> !   int param_count;
> !
> !   /* Number of statements already walked by when analyzing this function.  */
> !   unsigned int aa_walked;
>   };
>
>   /* Vector where the parameter infos are actually stored. */
> *************** ipa_binfo_from_known_type_jfunc (struct
> *** 510,515 ****
> --- 549,564 ----
>                               jfunc->value.known_type.component_type);
>   }
>
> + /* Get IPA BB information about the given BB.  FBI is the context of analyzis
> +    of this function body.  */
> +
> + static struct ipa_bb_info *
> + ipa_get_bb_info (struct func_body_info *fbi, basic_block bb)
> + {
> +   gcc_checking_assert (fbi);
> +   return &fbi->ibbis[bb->index];
> + }
> +
>   /* Structure to be passed in between detect_type_change and
>      check_stmt_for_type_change.  */
>
> *************** mark_modified (ao_ref *ao ATTRIBUTE_UNUS
> *** 769,802 ****
>     return true;
>   }
>
>   /* Return true if a load from a formal parameter PARM_LOAD is known to retrieve
>      a value known not to be modified in this function before reaching the
> !    statement STMT.  PARM_AINFO is a pointer to a structure containing temporary
> !    information about the parameter.  */
>
>   static bool
> ! parm_preserved_before_stmt_p (struct param_analysis_info *parm_ainfo,
> !                              gimple stmt, tree parm_load)
>   {
>     bool modified = false;
> -   bitmap *visited_stmts;
>     ao_ref refd;
>
> !   if (parm_ainfo && parm_ainfo->parm_modified)
> !     return false;
>
>     gcc_checking_assert (gimple_vuse (stmt) != NULL_TREE);
>     ao_ref_init (&refd, parm_load);
> !   /* We can cache visited statements only when parm_ainfo is available and when
> !      we are looking at a naked load of the whole parameter.  */
> !   if (!parm_ainfo || TREE_CODE (parm_load) != PARM_DECL)
> !     visited_stmts = NULL;
> !   else
> !     visited_stmts = &parm_ainfo->parm_visited_statements;
> !   walk_aliased_vdefs (&refd, gimple_vuse (stmt), mark_modified, &modified,
> !                     visited_stmts);
> !   if (parm_ainfo && modified)
> !     parm_ainfo->parm_modified = true;
>     return !modified;
>   }
>
> --- 818,918 ----
>     return true;
>   }
>
> + /* Return true if we have already walked so many statements in AA that we
> +    should really just start giving up.  */
> +
> + static bool
> + aa_overwalked (struct func_body_info *fbi)
> + {
> +   gcc_checking_assert (fbi);
> +   return fbi->aa_walked > (unsigned) PARAM_VALUE (PARAM_IPA_MAX_AA_STEPS);
> + }
> +
> + /* Find the nearest valid aa status for parameter specified by INDEX that
> +    dominates BB.  */
> +
> + static struct param_aa_status *
> + find_dominating_aa_status (struct func_body_info *fbi, basic_block bb,
> +                          int index)
> + {
> +   while (true)
> +     {
> +       bb = get_immediate_dominator (CDI_DOMINATORS, bb);
> +       if (!bb)
> +       return NULL;
> +       struct ipa_bb_info *bi = ipa_get_bb_info (fbi, bb);
> +       if (!bi->paas.is_empty ()
> +         && bi->paas[index].valid)
> +       return &bi->paas[index];
> +     }
> + }
> +
> + /* Get AA status structure for the given BB and parameter with INDEX.  Allocate
> +    structures and/or intialize the result with a dominating description as
> +    necessary.  */
> +
> + static struct param_aa_status *
> + parm_bb_aa_status_for_bb (struct func_body_info *fbi, basic_block bb,
> +                         int index)
> + {
> +   gcc_checking_assert (fbi);
> +   struct ipa_bb_info *bi = ipa_get_bb_info (fbi, bb);
> +   if (bi->paas.is_empty ())
> +     bi->paas.safe_grow_cleared (fbi->param_count);
> +   struct param_aa_status *paa = &bi->paas[index];
> +   if (!paa->valid)
> +     {
> +       gcc_checking_assert (!paa->parm_modified
> +                          && !paa->ref_modified
> +                          && !paa->pt_modified);
> +       struct param_aa_status *dom_paa;
> +       dom_paa = find_dominating_aa_status (fbi, bb, index);
> +       if (dom_paa)
> +       *paa = *dom_paa;
> +       else
> +       paa->valid = true;
> +     }
> +
> +   return paa;
> + }
> +
>   /* Return true if a load from a formal parameter PARM_LOAD is known to retrieve
>      a value known not to be modified in this function before reaching the
> !    statement STMT.  FBI holds information about the function we have so far
> !    gathered but do not survive the summary building stage.  */
>
>   static bool
> ! parm_preserved_before_stmt_p (struct func_body_info *fbi, int index,
> !                             gimple stmt, tree parm_load)
>   {
> +   struct param_aa_status *paa;
>     bool modified = false;
>     ao_ref refd;
>
> !   /* FIXME: FBI can be NULL if we are being called from outside
> !      ipa_node_analysis or ipcp_transform_function, which currently happens
> !      during inlining analysis.  It would be great to extend fbi's lifetime and
> !      always have it.  Currently, we are just not afraid of too much walking in
> !      that case.  */
> !   if (fbi)
> !     {
> !       if (aa_overwalked (fbi))
> !       return false;
> !       paa = parm_bb_aa_status_for_bb (fbi, gimple_bb (stmt), index);
> !       if (paa->parm_modified)
> !       return false;
> !     }
> !   else
> !     paa = NULL;
>
>     gcc_checking_assert (gimple_vuse (stmt) != NULL_TREE);
>     ao_ref_init (&refd, parm_load);
> !   int walked = walk_aliased_vdefs (&refd, gimple_vuse (stmt), mark_modified,
> !                                  &modified, NULL);
> !   if (fbi)
> !     fbi->aa_walked += walked;
> !   if (paa && modified)
> !     paa->parm_modified = true;
>     return !modified;
>   }
>
> *************** parm_preserved_before_stmt_p (struct par
> *** 805,812 ****
>      modified.  Otherwise return -1.  */
>
>   static int
> ! load_from_unmodified_param (vec<ipa_param_descriptor> descriptors,
> !                           struct param_analysis_info *parms_ainfo,
>                             gimple stmt)
>   {
>     int index;
> --- 921,928 ----
>      modified.  Otherwise return -1.  */
>
>   static int
> ! load_from_unmodified_param (struct func_body_info *fbi,
> !                           vec<ipa_param_descriptor> descriptors,
>                             gimple stmt)
>   {
>     int index;
> *************** load_from_unmodified_param (vec<ipa_para
> *** 821,865 ****
>
>     index = ipa_get_param_decl_index_1 (descriptors, op1);
>     if (index < 0
> !       || !parm_preserved_before_stmt_p (parms_ainfo ? &parms_ainfo[index]
> !                                       : NULL, stmt, op1))
>       return -1;
>
>     return index;
>   }
>
> ! /* Return true if memory reference REF loads data that are known to be
> !    unmodified in this function before reaching statement STMT.  PARM_AINFO, if
> !    non-NULL, is a pointer to a structure containing temporary information about
> !    PARM.  */
>
>   static bool
> ! parm_ref_data_preserved_p (struct param_analysis_info *parm_ainfo,
> !                             gimple stmt, tree ref)
>   {
>     bool modified = false;
>     ao_ref refd;
>
> !   gcc_checking_assert (gimple_vuse (stmt));
> !   if (parm_ainfo && parm_ainfo->ref_modified)
> !     return false;
>
>     ao_ref_init (&refd, ref);
> !   walk_aliased_vdefs (&refd, gimple_vuse (stmt), mark_modified, &modified,
> !                     NULL);
> !   if (parm_ainfo && modified)
> !     parm_ainfo->ref_modified = true;
>     return !modified;
>   }
>
> ! /* Return true if the data pointed to by PARM is known to be unmodified in this
> !    function before reaching call statement CALL into which it is passed.
> !    PARM_AINFO is a pointer to a structure containing temporary information
> !    about PARM.  */
>
>   static bool
> ! parm_ref_data_pass_through_p (struct param_analysis_info *parm_ainfo,
> !                              gimple call, tree parm)
>   {
>     bool modified = false;
>     ao_ref refd;
> --- 937,995 ----
>
>     index = ipa_get_param_decl_index_1 (descriptors, op1);
>     if (index < 0
> !       || !parm_preserved_before_stmt_p (fbi, index, stmt, op1))
>       return -1;
>
>     return index;
>   }
>
> ! /* Return true if memory reference REF (which must be a load through parameter
> !    with INDEX) loads data that are known to be unmodified in this function
> !    before reaching statement STMT.  */
>
>   static bool
> ! parm_ref_data_preserved_p (struct func_body_info *fbi,
> !                          int index, gimple stmt, tree ref)
>   {
> +   struct param_aa_status *paa;
>     bool modified = false;
>     ao_ref refd;
>
> !   /* FIXME: FBI can be NULL if we are being called from outside
> !      ipa_node_analysis or ipcp_transform_function, which currently happens
> !      during inlining analysis.  It would be great to extend fbi's lifetime and
> !      always have it.  Currently, we are just not afraid of too much walking in
> !      that case.  */
> !   if (fbi)
> !     {
> !       if (aa_overwalked (fbi))
> !       return false;
> !       paa = parm_bb_aa_status_for_bb (fbi, gimple_bb (stmt), index);
> !       if (paa->ref_modified)
> !       return false;
> !     }
> !   else
> !     paa = NULL;
>
> +   gcc_checking_assert (gimple_vuse (stmt));
>     ao_ref_init (&refd, ref);
> !   int walked = walk_aliased_vdefs (&refd, gimple_vuse (stmt), mark_modified,
> !                                  &modified, NULL);
> !   if (fbi)
> !     fbi->aa_walked += walked;
> !   if (paa && modified)
> !     paa->ref_modified = true;
>     return !modified;
>   }
>
> ! /* Return true if the data pointed to by PARM (which is a parameter with INDEX)
> !    is known to be unmodified in this function before reaching call statement
> !    CALL into which it is passed.  PARM_AINFO is a pointer to a structure
> !    containing temporary information about PARM.  */
>
>   static bool
> ! parm_ref_data_pass_through_p (struct func_body_info *fbi, int index,
> !                             gimple call, tree parm)
>   {
>     bool modified = false;
>     ao_ref refd;
> *************** parm_ref_data_pass_through_p (struct par
> *** 868,884 ****
>        function because it is not goin to use it.  But do not cache the result
>        either.  Also, no such calculations for non-pointers.  */
>     if (!gimple_vuse (call)
> !       || !POINTER_TYPE_P (TREE_TYPE (parm)))
>       return false;
>
> !   if (parm_ainfo->pt_modified)
>       return false;
>
>     ao_ref_init_from_ptr_and_size (&refd, parm, NULL_TREE);
> !   walk_aliased_vdefs (&refd, gimple_vuse (call), mark_modified, &modified,
> !                     parm_ainfo ? &parm_ainfo->pt_visited_statements : NULL);
>     if (modified)
> !     parm_ainfo->pt_modified = true;
>     return !modified;
>   }
>
> --- 998,1018 ----
>        function because it is not goin to use it.  But do not cache the result
>        either.  Also, no such calculations for non-pointers.  */
>     if (!gimple_vuse (call)
> !       || !POINTER_TYPE_P (TREE_TYPE (parm))
> !       || aa_overwalked (fbi))
>       return false;
>
> !   struct param_aa_status *paa = parm_bb_aa_status_for_bb (fbi, gimple_bb (call),
> !                                                         index);
> !   if (paa->pt_modified)
>       return false;
>
>     ao_ref_init_from_ptr_and_size (&refd, parm, NULL_TREE);
> !   int walked = walk_aliased_vdefs (&refd, gimple_vuse (call), mark_modified,
> !                                  &modified, NULL);
> !   fbi->aa_walked += walked;
>     if (modified)
> !     paa->pt_modified = true;
>     return !modified;
>   }
>
> *************** parm_ref_data_pass_through_p (struct par
> *** 893,902 ****
>      reference respectively.  */
>
>   static bool
> ! ipa_load_from_parm_agg_1 (vec<ipa_param_descriptor> descriptors,
> !                         struct param_analysis_info *parms_ainfo, gimple stmt,
> !                         tree op, int *index_p, HOST_WIDE_INT *offset_p,
> !                         HOST_WIDE_INT *size_p, bool *by_ref_p)
>   {
>     int index;
>     HOST_WIDE_INT size, max_size;
> --- 1027,1037 ----
>      reference respectively.  */
>
>   static bool
> ! ipa_load_from_parm_agg_1 (struct func_body_info *fbi,
> !                         vec<ipa_param_descriptor> descriptors,
> !                         gimple stmt, tree op, int *index_p,
> !                         HOST_WIDE_INT *offset_p, HOST_WIDE_INT *size_p,
> !                         bool *by_ref_p)
>   {
>     int index;
>     HOST_WIDE_INT size, max_size;
> *************** ipa_load_from_parm_agg_1 (vec<ipa_param_
> *** 909,916 ****
>       {
>         int index = ipa_get_param_decl_index_1 (descriptors, base);
>         if (index >= 0
> !         && parm_preserved_before_stmt_p (parms_ainfo ? &parms_ainfo[index]
> !                                          : NULL, stmt, op))
>         {
>           *index_p = index;
>           *by_ref_p = false;
> --- 1044,1050 ----
>       {
>         int index = ipa_get_param_decl_index_1 (descriptors, base);
>         if (index >= 0
> !         && parm_preserved_before_stmt_p (fbi, index, stmt, op))
>         {
>           *index_p = index;
>           *by_ref_p = false;
> *************** ipa_load_from_parm_agg_1 (vec<ipa_param_
> *** 949,960 ****
>         */
>
>         gimple def = SSA_NAME_DEF_STMT (TREE_OPERAND (base, 0));
> !       index = load_from_unmodified_param (descriptors, parms_ainfo, def);
>       }
>
>     if (index >= 0
> !       && parm_ref_data_preserved_p (parms_ainfo ? &parms_ainfo[index] : NULL,
> !                                   stmt, op))
>       {
>         *index_p = index;
>         *by_ref_p = true;
> --- 1083,1093 ----
>         */
>
>         gimple def = SSA_NAME_DEF_STMT (TREE_OPERAND (base, 0));
> !       index = load_from_unmodified_param (fbi, descriptors, def);
>       }
>
>     if (index >= 0
> !       && parm_ref_data_preserved_p (fbi, index, stmt, op))
>       {
>         *index_p = index;
>         *by_ref_p = true;
> *************** ipa_load_from_parm_agg (struct ipa_node_
> *** 973,979 ****
>                         tree op, int *index_p, HOST_WIDE_INT *offset_p,
>                         bool *by_ref_p)
>   {
> !   return ipa_load_from_parm_agg_1 (info->descriptors, NULL, stmt, op, index_p,
>                                    offset_p, NULL, by_ref_p);
>   }
>
> --- 1106,1112 ----
>                         tree op, int *index_p, HOST_WIDE_INT *offset_p,
>                         bool *by_ref_p)
>   {
> !   return ipa_load_from_parm_agg_1 (NULL, info->descriptors, stmt, op, index_p,
>                                    offset_p, NULL, by_ref_p);
>   }
>
> *************** ipa_load_from_parm_agg (struct ipa_node_
> *** 1031,1038 ****
>      only needed for intraprocedural analysis.  */
>
>   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,
>                                   tree param_type)
> --- 1164,1171 ----
>      only needed for intraprocedural analysis.  */
>
>   static void
> ! compute_complex_assign_jump_func (struct func_body_info *fbi,
> !                                 struct ipa_node_params *info,
>                                   struct ipa_jump_func *jfunc,
>                                   gimple call, gimple stmt, tree name,
>                                   tree param_type)
> *************** compute_complex_assign_jump_func (struct
> *** 1048,1060 ****
>         if (SSA_NAME_IS_DEFAULT_DEF (op1))
>         index = ipa_get_param_decl_index (info, SSA_NAME_VAR (op1));
>         else
> !       index = load_from_unmodified_param (info->descriptors, parms_ainfo,
>                                             SSA_NAME_DEF_STMT (op1));
>         tc_ssa = op1;
>       }
>     else
>       {
> !       index = load_from_unmodified_param (info->descriptors, parms_ainfo, stmt);
>         tc_ssa = gimple_assign_lhs (stmt);
>       }
>
> --- 1181,1193 ----
>         if (SSA_NAME_IS_DEFAULT_DEF (op1))
>         index = ipa_get_param_decl_index (info, SSA_NAME_VAR (op1));
>         else
> !       index = load_from_unmodified_param (fbi, info->descriptors,
>                                             SSA_NAME_DEF_STMT (op1));
>         tc_ssa = op1;
>       }
>     else
>       {
> !       index = load_from_unmodified_param (fbi, info->descriptors, stmt);
>         tc_ssa = gimple_assign_lhs (stmt);
>       }
>
> *************** compute_complex_assign_jump_func (struct
> *** 1075,1082 ****
>         }
>         else if (gimple_assign_single_p (stmt))
>         {
> !         bool agg_p = parm_ref_data_pass_through_p (&parms_ainfo[index],
> !                                                    call, tc_ssa);
>           bool type_p = false;
>
>           if (param_type && POINTER_TYPE_P (param_type))
> --- 1208,1214 ----
>         }
>         else if (gimple_assign_single_p (stmt))
>         {
> !         bool agg_p = parm_ref_data_pass_through_p (fbi, index, call, tc_ssa);
>           bool type_p = false;
>
>           if (param_type && POINTER_TYPE_P (param_type))
> *************** compute_complex_assign_jump_func (struct
> *** 1115,1121 ****
>         if (type_p || jfunc->type == IPA_JF_UNKNOWN)
>         ipa_set_ancestor_jf (jfunc, offset,
>                              type_p ? TREE_TYPE (param_type) : NULL, index,
> !                            parm_ref_data_pass_through_p (&parms_ainfo[index],
>                                                            call, ssa), type_p);
>       }
>   }
> --- 1247,1253 ----
>         if (type_p || jfunc->type == IPA_JF_UNKNOWN)
>         ipa_set_ancestor_jf (jfunc, offset,
>                              type_p ? TREE_TYPE (param_type) : NULL, index,
> !                            parm_ref_data_pass_through_p (fbi, index,
>                                                            call, ssa), type_p);
>       }
>   }
> *************** get_ancestor_addr_info (gimple assign, t
> *** 1187,1194 ****
>        return D.1879_6;  */
>
>   static void
> ! compute_complex_ancestor_jump_func (struct ipa_node_params *info,
> !                                   struct param_analysis_info *parms_ainfo,
>                                     struct ipa_jump_func *jfunc,
>                                     gimple call, gimple phi, tree param_type)
>   {
> --- 1319,1326 ----
>        return D.1879_6;  */
>
>   static void
> ! compute_complex_ancestor_jump_func (struct func_body_info *fbi,
> !                                   struct ipa_node_params *info,
>                                     struct ipa_jump_func *jfunc,
>                                     gimple call, gimple phi, tree param_type)
>   {
> *************** compute_complex_ancestor_jump_func (stru
> *** 1247,1255 ****
>       type_p = !detect_type_change (obj, expr, TREE_TYPE (param_type),
>                                   call, jfunc, offset);
>     if (type_p || jfunc->type == IPA_JF_UNKNOWN)
> !     ipa_set_ancestor_jf (jfunc, offset, type_p ? TREE_TYPE (param_type) : NULL, index,
> !                        parm_ref_data_pass_through_p (&parms_ainfo[index],
> !                                                      call, parm), type_p);
>   }
>
>   /* Given OP which is passed as an actual argument to a called function,
> --- 1379,1388 ----
>       type_p = !detect_type_change (obj, expr, TREE_TYPE (param_type),
>                                   call, jfunc, offset);
>     if (type_p || jfunc->type == IPA_JF_UNKNOWN)
> !     ipa_set_ancestor_jf (jfunc, offset, type_p ? TREE_TYPE (param_type) : NULL,
> !                        index,
> !                        parm_ref_data_pass_through_p (fbi, index, call, parm),
> !                        type_p);
>   }
>
>   /* Given OP which is passed as an actual argument to a called function,
> *************** ipa_get_callee_param_type (struct cgraph
> *** 1594,1600 ****
>      to this callsite.  */
>
>   static void
> ! 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);
> --- 1727,1733 ----
>      to this callsite.  */
>
>   static void
> ! ipa_compute_jump_functions_for_edge (struct func_body_info *fbi,
>                                      struct cgraph_edge *cs)
>   {
>     struct ipa_node_params *info = IPA_NODE_REF (cs->caller);
> *************** ipa_compute_jump_functions_for_edge (str
> *** 1628,1634 ****
>           /* Aggregate passed by value, check for pass-through, otherwise we
>              will attempt to fill in aggregate contents later in this
>              for cycle.  */
> !         if (parm_preserved_before_stmt_p (&parms_ainfo[index], call, arg))
>             {
>               ipa_set_jf_simple_pass_through (jfunc, index, false, false);
>               continue;
> --- 1761,1767 ----
>           /* Aggregate passed by value, check for pass-through, otherwise we
>              will attempt to fill in aggregate contents later in this
>              for cycle.  */
> !         if (parm_preserved_before_stmt_p (fbi, index, call, arg))
>             {
>               ipa_set_jf_simple_pass_through (jfunc, index, false, false);
>               continue;
> *************** ipa_compute_jump_functions_for_edge (str
> *** 1642,1649 ****
>               if (index >= 0)
>                 {
>                   bool agg_p, type_p;
> !                 agg_p = parm_ref_data_pass_through_p (&parms_ainfo[index],
> !                                                       call, arg);
>                   if (param_type && POINTER_TYPE_P (param_type))
>                     type_p = !detect_type_change_ssa (arg, TREE_TYPE (param_type),
>                                                       call, jfunc);
> --- 1775,1781 ----
>               if (index >= 0)
>                 {
>                   bool agg_p, type_p;
> !                 agg_p = parm_ref_data_pass_through_p (fbi, index, call, arg);
>                   if (param_type && POINTER_TYPE_P (param_type))
>                     type_p = !detect_type_change_ssa (arg, TREE_TYPE (param_type),
>                                                       call, jfunc);
> *************** ipa_compute_jump_functions_for_edge (str
> *** 1658,1667 ****
>             {
>               gimple stmt = SSA_NAME_DEF_STMT (arg);
>               if (is_gimple_assign (stmt))
> !               compute_complex_assign_jump_func (info, parms_ainfo, jfunc,
>                                                   call, stmt, arg, param_type);
>               else if (gimple_code (stmt) == GIMPLE_PHI)
> !               compute_complex_ancestor_jump_func (info, parms_ainfo, jfunc,
>                                                     call, stmt, param_type);
>             }
>         }
> --- 1790,1799 ----
>             {
>               gimple stmt = SSA_NAME_DEF_STMT (arg);
>               if (is_gimple_assign (stmt))
> !               compute_complex_assign_jump_func (fbi, info, jfunc,
>                                                   call, stmt, arg, param_type);
>               else if (gimple_code (stmt) == GIMPLE_PHI)
> !               compute_complex_ancestor_jump_func (fbi, info, jfunc,
>                                                     call, stmt, param_type);
>             }
>         }
> *************** ipa_compute_jump_functions_for_edge (str
> *** 1692,1718 ****
>   }
>
>   /* Compute jump functions for all edges - both direct and indirect - outgoing
> !    from NODE.  Also count the actual arguments in the process.  */
>
>   static void
> ! ipa_compute_jump_functions (struct cgraph_node *node,
> !                           struct param_analysis_info *parms_ainfo)
>   {
>     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.  */
> !       if (!callee->definition && !flag_lto)
> !       continue;
> !       ipa_compute_jump_functions_for_edge (parms_ainfo, cs);
> !     }
>
> !   for (cs = node->indirect_calls; cs; cs = cs->next_callee)
> !     ipa_compute_jump_functions_for_edge (parms_ainfo, cs);
>   }
>
>   /* If STMT looks like a statement loading a value from a member pointer formal
> --- 1824,1852 ----
>   }
>
>   /* Compute jump functions for all edges - both direct and indirect - outgoing
> !    from BB.  */
>
>   static void
> ! ipa_compute_jump_functions_for_bb (struct func_body_info *fbi, basic_block bb)
>   {
> +   struct ipa_bb_info *bi = ipa_get_bb_info (fbi, bb);
> +   int i;
>     struct cgraph_edge *cs;
>
> !   FOR_EACH_VEC_ELT_REVERSE (bi->cg_edges, i, cs)
>       {
> !       struct cgraph_node *callee = cs->callee;
>
> !       if (callee)
> !       {
> !         cgraph_function_or_thunk_node (callee, NULL);
> !         /* We do not need to bother analyzing calls to unknown functions
> !            unless they may become known during lto/whopr.  */
> !         if (!callee->definition && !flag_lto)
> !           continue;
> !       }
> !       ipa_compute_jump_functions_for_edge (fbi, cs);
> !     }
>   }
>
>   /* If STMT looks like a statement loading a value from a member pointer formal
> *************** ipa_note_param_call (struct cgraph_node
> *** 1855,1891 ****
>      passed by value or reference.  */
>
>   static void
> ! ipa_analyze_indirect_call_uses (struct cgraph_node *node,
> !                               struct ipa_node_params *info,
> !                               struct param_analysis_info *parms_ainfo,
> !                               gimple call, tree target)
> ! {
> !   gimple def;
> !   tree n1, n2;
> !   gimple d1, d2;
> !   tree rec, rec2, cond;
> !   gimple branch;
> !   int index;
> !   basic_block bb, virt_bb, join;
>     HOST_WIDE_INT offset;
>     bool by_ref;
>
>     if (SSA_NAME_IS_DEFAULT_DEF (target))
>       {
>         tree var = SSA_NAME_VAR (target);
> !       index = ipa_get_param_decl_index (info, var);
>         if (index >= 0)
> !       ipa_note_param_call (node, index, call);
>         return;
>       }
>
> !   def = SSA_NAME_DEF_STMT (target);
>     if (gimple_assign_single_p (def)
> !       && ipa_load_from_parm_agg_1 (info->descriptors, parms_ainfo, def,
>                                    gimple_assign_rhs1 (def), &index, &offset,
>                                    NULL, &by_ref))
>       {
> !       struct cgraph_edge *cs = ipa_note_param_call (node, index, call);
>         if (cs->indirect_info->offset != offset)
>         cs->indirect_info->outer_type = NULL;
>         cs->indirect_info->offset = offset;
> --- 1989,2018 ----
>      passed by value or reference.  */
>
>   static void
> ! ipa_analyze_indirect_call_uses (struct func_body_info *fbi, gimple call,
> !                               tree target)
> ! {
> !   struct ipa_node_params *info = fbi->info;
>     HOST_WIDE_INT offset;
>     bool by_ref;
>
>     if (SSA_NAME_IS_DEFAULT_DEF (target))
>       {
>         tree var = SSA_NAME_VAR (target);
> !       int index = ipa_get_param_decl_index (info, var);
>         if (index >= 0)
> !       ipa_note_param_call (fbi->node, index, call);
>         return;
>       }
>
> !   int index;
> !   gimple def = SSA_NAME_DEF_STMT (target);
>     if (gimple_assign_single_p (def)
> !       && ipa_load_from_parm_agg_1 (fbi, info->descriptors, def,
>                                    gimple_assign_rhs1 (def), &index, &offset,
>                                    NULL, &by_ref))
>       {
> !       struct cgraph_edge *cs = ipa_note_param_call (fbi->node, index, call);
>         if (cs->indirect_info->offset != offset)
>         cs->indirect_info->outer_type = NULL;
>         cs->indirect_info->offset = offset;
> *************** ipa_analyze_indirect_call_uses (struct c
> *** 1904,1917 ****
>
>     /* First, we need to check whether one of these is a load from a member
>        pointer that is a parameter to this function. */
> !   n1 = PHI_ARG_DEF (def, 0);
> !   n2 = PHI_ARG_DEF (def, 1);
>     if (!ipa_is_ssa_with_stmt_def (n1) || !ipa_is_ssa_with_stmt_def (n2))
>       return;
> !   d1 = SSA_NAME_DEF_STMT (n1);
> !   d2 = SSA_NAME_DEF_STMT (n2);
>
> !   join = gimple_bb (def);
>     if ((rec = ipa_get_stmt_member_ptr_load_param (d1, false, &offset)))
>       {
>         if (ipa_get_stmt_member_ptr_load_param (d2, false, NULL))
> --- 2031,2046 ----
>
>     /* First, we need to check whether one of these is a load from a member
>        pointer that is a parameter to this function. */
> !   tree n1 = PHI_ARG_DEF (def, 0);
> !   tree n2 = PHI_ARG_DEF (def, 1);
>     if (!ipa_is_ssa_with_stmt_def (n1) || !ipa_is_ssa_with_stmt_def (n2))
>       return;
> !   gimple d1 = SSA_NAME_DEF_STMT (n1);
> !   gimple d2 = SSA_NAME_DEF_STMT (n2);
>
> !   tree rec;
> !   basic_block bb, virt_bb;
> !   basic_block join = gimple_bb (def);
>     if ((rec = ipa_get_stmt_member_ptr_load_param (d1, false, &offset)))
>       {
>         if (ipa_get_stmt_member_ptr_load_param (d2, false, NULL))
> *************** ipa_analyze_indirect_call_uses (struct c
> *** 1939,1945 ****
>     /* Third, let's see that the branching is done depending on the least
>        significant bit of the pfn. */
>
> !   branch = last_stmt (bb);
>     if (!branch || gimple_code (branch) != GIMPLE_COND)
>       return;
>
> --- 2068,2074 ----
>     /* Third, let's see that the branching is done depending on the least
>        significant bit of the pfn. */
>
> !   gimple branch = last_stmt (bb);
>     if (!branch || gimple_code (branch) != GIMPLE_COND)
>       return;
>
> *************** ipa_analyze_indirect_call_uses (struct c
> *** 1948,1954 ****
>         || !integer_zerop (gimple_cond_rhs (branch)))
>       return;
>
> !   cond = gimple_cond_lhs (branch);
>     if (!ipa_is_ssa_with_stmt_def (cond))
>       return;
>
> --- 2077,2083 ----
>         || !integer_zerop (gimple_cond_rhs (branch)))
>       return;
>
> !   tree cond = gimple_cond_lhs (branch);
>     if (!ipa_is_ssa_with_stmt_def (cond))
>       return;
>
> *************** ipa_analyze_indirect_call_uses (struct c
> *** 1973,1978 ****
> --- 2102,2108 ----
>         def = SSA_NAME_DEF_STMT (cond);
>       }
>
> +   tree rec2;
>     rec2 = ipa_get_stmt_member_ptr_load_param (def,
>                                              (TARGET_PTRMEMFUNC_VBIT_LOCATION
>                                               == ptrmemfunc_vbit_in_delta),
> *************** ipa_analyze_indirect_call_uses (struct c
> *** 1982,1990 ****
>
>     index = ipa_get_param_decl_index (info, rec);
>     if (index >= 0
> !       && parm_preserved_before_stmt_p (&parms_ainfo[index], call, rec))
>       {
> !       struct cgraph_edge *cs = ipa_note_param_call (node, index, call);
>         if (cs->indirect_info->offset != offset)
>         cs->indirect_info->outer_type = NULL;
>         cs->indirect_info->offset = offset;
> --- 2112,2120 ----
>
>     index = ipa_get_param_decl_index (info, rec);
>     if (index >= 0
> !       && parm_preserved_before_stmt_p (fbi, index, call, rec))
>       {
> !       struct cgraph_edge *cs = ipa_note_param_call (fbi->node, index, call);
>         if (cs->indirect_info->offset != offset)
>         cs->indirect_info->outer_type = NULL;
>         cs->indirect_info->offset = offset;
> *************** ipa_analyze_indirect_call_uses (struct c
> *** 1997,2012 ****
>
>   /* Analyze a CALL to an OBJ_TYPE_REF which is passed in TARGET and if the
>      object referenced in the expression is a formal parameter of the caller
> !    (described by INFO), create a call note for the statement. */
>
>   static void
> ! ipa_analyze_virtual_call_uses (struct cgraph_node *node,
> !                              struct ipa_node_params *info, gimple call,
> !                              tree target)
>   {
> -   struct cgraph_edge *cs;
> -   struct cgraph_indirect_call_info *ii;
> -   struct ipa_jump_func jfunc;
>     tree obj = OBJ_TYPE_REF_OBJECT (target);
>     int index;
>     HOST_WIDE_INT anc_offset;
> --- 2127,2139 ----
>
>   /* Analyze a CALL to an OBJ_TYPE_REF which is passed in TARGET and if the
>      object referenced in the expression is a formal parameter of the caller
> !    FBI->node (described by FBI->info), create a call note for the
> !    statement.  */
>
>   static void
> ! ipa_analyze_virtual_call_uses (struct func_body_info *fbi,
> !                              gimple call, tree target)
>   {
>     tree obj = OBJ_TYPE_REF_OBJECT (target);
>     int index;
>     HOST_WIDE_INT anc_offset;
> *************** ipa_analyze_virtual_call_uses (struct cg
> *** 2017,2024 ****
> --- 2144,2153 ----
>     if (TREE_CODE (obj) != SSA_NAME)
>       return;
>
> +   struct ipa_node_params *info = fbi->info;
>     if (SSA_NAME_IS_DEFAULT_DEF (obj))
>       {
> +       struct ipa_jump_func jfunc;
>         if (TREE_CODE (SSA_NAME_VAR (obj)) != PARM_DECL)
>         return;
>
> *************** ipa_analyze_virtual_call_uses (struct cg
> *** 2031,2036 ****
> --- 2160,2166 ----
>       }
>     else
>       {
> +       struct ipa_jump_func jfunc;
>         gimple stmt = SSA_NAME_DEF_STMT (obj);
>         tree expr;
>
> *************** ipa_analyze_virtual_call_uses (struct cg
> *** 2045,2052 ****
>         return;
>       }
>
> !   cs = ipa_note_param_call (node, index, call);
> !   ii = cs->indirect_info;
>     ii->offset = anc_offset;
>     ii->otr_token = tree_to_uhwi (OBJ_TYPE_REF_TOKEN (target));
>     ii->otr_type = obj_type_ref_class (target);
> --- 2175,2182 ----
>         return;
>       }
>
> !   struct cgraph_edge *cs = ipa_note_param_call (fbi->node, index, call);
> !   struct cgraph_indirect_call_info *ii = cs->indirect_info;
>     ii->offset = anc_offset;
>     ii->otr_token = tree_to_uhwi (OBJ_TYPE_REF_TOKEN (target));
>     ii->otr_type = obj_type_ref_class (target);
> *************** ipa_analyze_virtual_call_uses (struct cg
> *** 2058,2069 ****
>      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_ainfo, gimple call)
>   {
>     tree target = gimple_call_fn (call);
> -   struct cgraph_edge *cs;
>
>     if (!target
>         || (TREE_CODE (target) != SSA_NAME
> --- 2188,2196 ----
>      containing intermediate information about each formal parameter.  */
>
>   static void
> ! ipa_analyze_call_uses (struct func_body_info *fbi, gimple call)
>   {
>     tree target = gimple_call_fn (call);
>
>     if (!target
>         || (TREE_CODE (target) != SSA_NAME
> *************** ipa_analyze_call_uses (struct cgraph_nod
> *** 2072,2098 ****
>
>     /* If we previously turned the call into a direct call, there is
>        no need to analyze.  */
> !   cs = cgraph_edge (node, call);
>     if (cs && !cs->indirect_unknown_callee)
>       return;
>     if (TREE_CODE (target) == SSA_NAME)
> !     ipa_analyze_indirect_call_uses (node, info, parms_ainfo, call, target);
>     else if (virtual_method_call_p (target))
> !     ipa_analyze_virtual_call_uses (node, info, call, target);
>   }
>
>
>   /* 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_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,
> !                      struct param_analysis_info *parms_ainfo, gimple stmt)
>   {
>     if (is_gimple_call (stmt))
> !     ipa_analyze_call_uses (node, info, parms_ainfo, stmt);
>   }
>
>   /* Callback of walk_stmt_load_store_addr_ops for the visit_load.
> --- 2199,2223 ----
>
>     /* If we previously turned the call into a direct call, there is
>        no need to analyze.  */
> !   struct cgraph_edge *cs = cgraph_edge (fbi->node, call);
>     if (cs && !cs->indirect_unknown_callee)
>       return;
>     if (TREE_CODE (target) == SSA_NAME)
> !     ipa_analyze_indirect_call_uses (fbi, call, target);
>     else if (virtual_method_call_p (target))
> !     ipa_analyze_virtual_call_uses (fbi, call, target);
>   }
>
>
>   /* Analyze the call statement STMT with respect to formal parameters (described
> !    in INFO) of caller given by FBI->NODE.  Currently it only checks whether
> !    formal parameters are called.  */
>
>   static void
> ! ipa_analyze_stmt_uses (struct func_body_info *fbi, gimple stmt)
>   {
>     if (is_gimple_call (stmt))
> !     ipa_analyze_call_uses (fbi, stmt);
>   }
>
>   /* Callback of walk_stmt_load_store_addr_ops for the visit_load.
> *************** visit_ref_for_mod_analysis (gimple, tree
> *** 2116,2152 ****
>     return false;
>   }
>
> ! /* 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_AINFO is a pointer to a
> !    vector containing intermediate information about each formal parameter.   */
>
>   static void
> ! ipa_analyze_params_uses (struct cgraph_node *node,
> !                        struct param_analysis_info *parms_ainfo)
>   {
> -   tree decl = node->decl;
> -   basic_block bb;
> -   struct function *func;
>     gimple_stmt_iterator gsi;
> !   struct ipa_node_params *info = IPA_NODE_REF (node);
> !   int i;
>
> !   if (ipa_get_param_count (info) == 0 || info->uses_analysis_done)
> !     return;
>
> !   info->uses_analysis_done = 1;
> !   if (ipa_func_spec_opts_forbid_analysis_p (node))
> !     {
> !       for (i = 0; i < ipa_get_param_count (info); i++)
> !       {
> !         ipa_set_param_used (info, i, true);
> !         ipa_set_controlled_uses (info, i, IPA_UNDESCRIBED_USE);
> !       }
> !       return;
> !     }
>
> !   for (i = 0; i < ipa_get_param_count (info); i++)
>       {
>         tree parm = ipa_get_param (info, i);
>         int controlled_uses = 0;
> --- 2241,2283 ----
>     return false;
>   }
>
> ! /* Scan the statements in BB 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.  FBI holds various data about
> !    the function being analyzed.  */
>
>   static void
> ! ipa_analyze_params_uses_in_bb (struct func_body_info *fbi, basic_block bb)
>   {
>     gimple_stmt_iterator gsi;
> !   for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
> !     {
> !       gimple stmt = gsi_stmt (gsi);
>
> !       if (is_gimple_debug (stmt))
> !       continue;
>
> !       ipa_analyze_stmt_uses (fbi, stmt);
> !       walk_stmt_load_store_addr_ops (stmt, fbi->info,
> !                                    visit_ref_for_mod_analysis,
> !                                    visit_ref_for_mod_analysis,
> !                                    visit_ref_for_mod_analysis);
> !     }
> !   for (gsi = gsi_start_phis (bb); !gsi_end_p (gsi); gsi_next (&gsi))
> !     walk_stmt_load_store_addr_ops (gsi_stmt (gsi), fbi->info,
> !                                  visit_ref_for_mod_analysis,
> !                                  visit_ref_for_mod_analysis,
> !                                  visit_ref_for_mod_analysis);
> ! }
> !
> ! /* Calculate controlled uses of parameters of NODE.  */
> !
> ! static void
> ! ipa_analyze_controlled_uses (struct cgraph_node *node)
> ! {
> !   struct ipa_node_params *info = IPA_NODE_REF (node);
>
> !   for (int i = 0; i < ipa_get_param_count (info); i++)
>       {
>         tree parm = ipa_get_param (info, i);
>         int controlled_uses = 0;
> *************** ipa_analyze_params_uses (struct cgraph_n
> *** 2182,2226 ****
>         controlled_uses = IPA_UNDESCRIBED_USE;
>         ipa_set_controlled_uses (info, i, controlled_uses);
>       }
>
> !   func = DECL_STRUCT_FUNCTION (decl);
> !   FOR_EACH_BB_FN (bb, func)
> !     {
> !       for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
> !       {
> !         gimple stmt = gsi_stmt (gsi);
> !
> !         if (is_gimple_debug (stmt))
> !           continue;
>
> !         ipa_analyze_stmt_uses (node, info, parms_ainfo, stmt);
> !         walk_stmt_load_store_addr_ops (stmt, info,
> !                                        visit_ref_for_mod_analysis,
> !                                        visit_ref_for_mod_analysis,
> !                                        visit_ref_for_mod_analysis);
> !       }
> !       for (gsi = gsi_start_phis (bb); !gsi_end_p (gsi); gsi_next (&gsi))
> !       walk_stmt_load_store_addr_ops (gsi_stmt (gsi), info,
> !                                      visit_ref_for_mod_analysis,
> !                                      visit_ref_for_mod_analysis,
> !                                      visit_ref_for_mod_analysis);
> !     }
>   }
>
> ! /* Free stuff in PARMS_AINFO, assume there are PARAM_COUNT parameters.  */
>
> ! static void
> ! free_parms_ainfo (struct param_analysis_info *parms_ainfo, int param_count)
>   {
> !   int i;
>
> !   for (i = 0; i < param_count; i++)
> !     {
> !       if (parms_ainfo[i].parm_visited_statements)
> !       BITMAP_FREE (parms_ainfo[i].parm_visited_statements);
> !       if (parms_ainfo[i].pt_visited_statements)
> !       BITMAP_FREE (parms_ainfo[i].pt_visited_statements);
> !     }
>   }
>
>   /* Initialize the array describing properties of of formal parameters
> --- 2313,2348 ----
>         controlled_uses = IPA_UNDESCRIBED_USE;
>         ipa_set_controlled_uses (info, i, controlled_uses);
>       }
> + }
>
> ! /* Free stuff in BI.  */
>
> ! static void
> ! free_ipa_bb_info (struct ipa_bb_info *bi)
> ! {
> !   bi->cg_edges.release ();
> !   bi->paas.release ();
>   }
>
> ! /* Dominator walker driving the analysis.  */
>
> ! class analysis_dom_walker : public dom_walker
>   {
> ! public:
> !   analysis_dom_walker (struct func_body_info *fbi)
> !     : dom_walker (CDI_DOMINATORS), m_fbi (fbi) {}
>
> !   virtual void before_dom_children (basic_block);
> !
> ! private:
> !   struct func_body_info *m_fbi;
> ! };
> !
> ! void
> ! analysis_dom_walker::before_dom_children (basic_block bb)
> ! {
> !   ipa_analyze_params_uses_in_bb (m_fbi, bb);
> !   ipa_compute_jump_functions_for_bb (m_fbi, bb);
>   }
>
>   /* Initialize the array describing properties of of formal parameters
> *************** free_parms_ainfo (struct param_analysis_
> *** 2230,2253 ****
>   void
>   ipa_analyze_node (struct cgraph_node *node)
>   {
>     struct ipa_node_params *info;
> -   struct param_analysis_info *parms_ainfo;
> -   int param_count;
>
>     ipa_check_create_node_params ();
>     ipa_check_create_edge_args ();
>     info = IPA_NODE_REF (node);
> !   push_cfun (DECL_STRUCT_FUNCTION (node->decl));
>     ipa_initialize_node_params (node);
>
> !   param_count = ipa_get_param_count (info);
> !   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_ainfo);
> !   ipa_compute_jump_functions (node, parms_ainfo);
>
> !   free_parms_ainfo (parms_ainfo, param_count);
>     pop_cfun ();
>   }
>
> --- 2352,2411 ----
>   void
>   ipa_analyze_node (struct cgraph_node *node)
>   {
> +   struct func_body_info fbi;
>     struct ipa_node_params *info;
>
>     ipa_check_create_node_params ();
>     ipa_check_create_edge_args ();
>     info = IPA_NODE_REF (node);
> !
> !   if (info->analysis_done)
> !     return;
> !   info->analysis_done = 1;
> !
> !   if (ipa_func_spec_opts_forbid_analysis_p (node))
> !     {
> !       for (int i = 0; i < ipa_get_param_count (info); i++)
> !       {
> !         ipa_set_param_used (info, i, true);
> !         ipa_set_controlled_uses (info, i, IPA_UNDESCRIBED_USE);
> !       }
> !       return;
> !     }
> !
> !   struct function *func = DECL_STRUCT_FUNCTION (node->decl);
> !   push_cfun (func);
> !   calculate_dominance_info (CDI_DOMINATORS);
>     ipa_initialize_node_params (node);
> +   ipa_analyze_controlled_uses (node);
>
> !   fbi.node = node;
> !   fbi.info = IPA_NODE_REF (node);
> !   fbi.ibbis = vNULL;
> !   fbi.ibbis.safe_grow_cleared (last_basic_block_for_fn (cfun));
> !   fbi.param_count = ipa_get_param_count (info);
> !   fbi.aa_walked = 0;
>
> !   for (struct cgraph_edge *cs = node->callees; cs; cs = cs->next_callee)
> !     {
> !       ipa_bb_info *bi = ipa_get_bb_info (&fbi, gimple_bb (cs->call_stmt));
> !       bi->cg_edges.safe_push (cs);
> !     }
>
> !   for (struct cgraph_edge *cs = node->indirect_calls; cs; cs = cs->next_callee)
> !     {
> !       ipa_bb_info *bi = ipa_get_bb_info (&fbi, gimple_bb (cs->call_stmt));
> !       bi->cg_edges.safe_push (cs);
> !     }
> !
> !   analysis_dom_walker (&fbi).walk (ENTRY_BLOCK_PTR_FOR_FN (cfun));
> !
> !   int i;
> !   struct ipa_bb_info *bi;
> !   FOR_EACH_VEC_ELT (fbi.ibbis, i, bi)
> !     free_ipa_bb_info (bi);
> !   fbi.ibbis.release ();
> !   free_dominance_info (CDI_DOMINATORS);
>     pop_cfun ();
>   }
>
> *************** ipa_node_duplication_hook (struct cgraph
> *** 3299,3305 ****
>     new_info->lattices = NULL;
>     new_info->ipcp_orig_node = old_info->ipcp_orig_node;
>
> !   new_info->uses_analysis_done = old_info->uses_analysis_done;
>     new_info->node_enqueued = old_info->node_enqueued;
>
>     old_av = ipa_get_agg_replacements_for_node (src);
> --- 3457,3463 ----
>     new_info->lattices = NULL;
>     new_info->ipcp_orig_node = old_info->ipcp_orig_node;
>
> !   new_info->analysis_done = old_info->analysis_done;
>     new_info->node_enqueued = old_info->node_enqueued;
>
>     old_av = ipa_get_agg_replacements_for_node (src);
> *************** ipa_write_node_info (struct output_block
> *** 4424,4430 ****
>     for (j = 0; j < ipa_get_param_count (info); j++)
>       streamer_write_uhwi (ob, ipa_get_param_move_cost (info, j));
>     bp = bitpack_create (ob->main_stream);
> !   gcc_assert (info->uses_analysis_done
>               || ipa_get_param_count (info) == 0);
>     gcc_assert (!info->node_enqueued);
>     gcc_assert (!info->ipcp_orig_node);
> --- 4582,4588 ----
>     for (j = 0; j < ipa_get_param_count (info); j++)
>       streamer_write_uhwi (ob, ipa_get_param_move_cost (info, j));
>     bp = bitpack_create (ob->main_stream);
> !   gcc_assert (info->analysis_done
>               || ipa_get_param_count (info) == 0);
>     gcc_assert (!info->node_enqueued);
>     gcc_assert (!info->ipcp_orig_node);
> *************** ipa_read_node_info (struct lto_input_blo
> *** 4470,4476 ****
>
>     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++)
>       ipa_set_param_used (info, k, bp_unpack_value (&bp, 1));
> --- 4628,4634 ----
>
>     bp = streamer_read_bitpack (ib);
>     if (ipa_get_param_count (info) != 0)
> !     info->analysis_done = true;
>     info->node_enqueued = false;
>     for (k = 0; k < ipa_get_param_count (info); k++)
>       ipa_set_param_used (info, k, bp_unpack_value (&bp, 1));
> *************** adjust_agg_replacement_values (struct cg
> *** 4820,4836 ****
>       v->index = adj[v->index];
>   }
>
>
> ! /* Function body transformation phase.  */
>
>   unsigned int
>   ipcp_transform_function (struct cgraph_node *node)
>   {
>     vec<ipa_param_descriptor> descriptors = vNULL;
> !   struct param_analysis_info *parms_ainfo;
>     struct ipa_agg_replacement_value *aggval;
> -   gimple_stmt_iterator gsi;
> -   basic_block bb;
>     int param_count;
>     bool cfg_changed = false, something_changed = false;
>
> --- 4978,5106 ----
>       v->index = adj[v->index];
>   }
>
> + /* Dominator walker driving the ipcp modification phase.  */
> +
> + class ipcp_modif_dom_walker : public dom_walker
> + {
> + public:
> +   ipcp_modif_dom_walker (struct func_body_info *fbi,
> +                        vec<ipa_param_descriptor> descs,
> +                        struct ipa_agg_replacement_value *av,
> +                        bool *sc, bool *cc)
> +     : dom_walker (CDI_DOMINATORS), m_fbi (fbi), m_descriptors (descs),
> +       m_aggval (av), m_something_changed (sc), m_cfg_changed (cc) {}
> +
> +   virtual void before_dom_children (basic_block);
> +
> + private:
> +   struct func_body_info *m_fbi;
> +   vec<ipa_param_descriptor> m_descriptors;
> +   struct ipa_agg_replacement_value *m_aggval;
> +   bool *m_something_changed, *m_cfg_changed;
> + };
> +
> + void
> + ipcp_modif_dom_walker::before_dom_children (basic_block bb)
> + {
> +   gimple_stmt_iterator gsi;
> +   for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
> +     {
> +       struct ipa_agg_replacement_value *v;
> +       gimple stmt = gsi_stmt (gsi);
> +       tree rhs, val, t;
> +       HOST_WIDE_INT offset, size;
> +       int index;
> +       bool by_ref, vce;
> +
> +       if (!gimple_assign_load_p (stmt))
> +       continue;
> +       rhs = gimple_assign_rhs1 (stmt);
> +       if (!is_gimple_reg_type (TREE_TYPE (rhs)))
> +       continue;
>
> !       vce = false;
> !       t = rhs;
> !       while (handled_component_p (t))
> !       {
> !         /* V_C_E can do things like convert an array of integers to one
> !            bigger integer and similar things we do not handle below.  */
> !         if (TREE_CODE (rhs) == VIEW_CONVERT_EXPR)
> !           {
> !             vce = true;
> !             break;
> !           }
> !         t = TREE_OPERAND (t, 0);
> !       }
> !       if (vce)
> !       continue;
> !
> !       if (!ipa_load_from_parm_agg_1 (m_fbi, m_descriptors, stmt, rhs, &index,
> !                                    &offset, &size, &by_ref))
> !       continue;
> !       for (v = m_aggval; v; v = v->next)
> !       if (v->index == index
> !           && v->offset == offset)
> !         break;
> !       if (!v
> !         || v->by_ref != by_ref
> !         || tree_to_shwi (TYPE_SIZE (TREE_TYPE (v->value))) != size)
> !       continue;
> !
> !       gcc_checking_assert (is_gimple_ip_invariant (v->value));
> !       if (!useless_type_conversion_p (TREE_TYPE (rhs), TREE_TYPE (v->value)))
> !       {
> !         if (fold_convertible_p (TREE_TYPE (rhs), v->value))
> !           val = fold_build1 (NOP_EXPR, TREE_TYPE (rhs), v->value);
> !         else if (TYPE_SIZE (TREE_TYPE (rhs))
> !                  == TYPE_SIZE (TREE_TYPE (v->value)))
> !           val = fold_build1 (VIEW_CONVERT_EXPR, TREE_TYPE (rhs), v->value);
> !         else
> !           {
> !             if (dump_file)
> !               {
> !                 fprintf (dump_file, "    const ");
> !                 print_generic_expr (dump_file, v->value, 0);
> !                 fprintf (dump_file, "  can't be converted to type of ");
> !                 print_generic_expr (dump_file, rhs, 0);
> !                 fprintf (dump_file, "\n");
> !               }
> !             continue;
> !           }
> !       }
> !       else
> !       val = v->value;
> !
> !       if (dump_file && (dump_flags & TDF_DETAILS))
> !       {
> !         fprintf (dump_file, "Modifying stmt:\n  ");
> !         print_gimple_stmt (dump_file, stmt, 0, 0);
> !       }
> !       gimple_assign_set_rhs_from_tree (&gsi, val);
> !       update_stmt (stmt);
> !
> !       if (dump_file && (dump_flags & TDF_DETAILS))
> !       {
> !         fprintf (dump_file, "into:\n  ");
> !         print_gimple_stmt (dump_file, stmt, 0, 0);
> !         fprintf (dump_file, "\n");
> !       }
> !
> !       *m_something_changed = true;
> !       if (maybe_clean_eh_stmt (stmt)
> !         && gimple_purge_dead_eh_edges (gimple_bb (stmt)))
> !       *m_cfg_changed = true;
> !     }
> !
> ! }
> !
> ! /* IPCP transformation phase doing propagation of aggregate values.  */
>
>   unsigned int
>   ipcp_transform_function (struct cgraph_node *node)
>   {
>     vec<ipa_param_descriptor> descriptors = vNULL;
> !   struct func_body_info fbi;
>     struct ipa_agg_replacement_value *aggval;
>     int param_count;
>     bool cfg_changed = false, something_changed = false;
>
> *************** ipcp_transform_function (struct cgraph_n
> *** 4850,4951 ****
>     adjust_agg_replacement_values (node, aggval);
>     if (dump_file)
>       ipa_dump_agg_replacement_values (dump_file, aggval);
> -   parms_ainfo = XALLOCAVEC (struct param_analysis_info, param_count);
> -   memset (parms_ainfo, 0, sizeof (struct param_analysis_info) * param_count);
> -   descriptors.safe_grow_cleared (param_count);
> -   ipa_populate_param_decls (node, descriptors);
> -
> -   FOR_EACH_BB_FN (bb, cfun)
> -     for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
> -       {
> -       struct ipa_agg_replacement_value *v;
> -       gimple stmt = gsi_stmt (gsi);
> -       tree rhs, val, t;
> -       HOST_WIDE_INT offset, size;
> -       int index;
> -       bool by_ref, vce;
> -
> -       if (!gimple_assign_load_p (stmt))
> -         continue;
> -       rhs = gimple_assign_rhs1 (stmt);
> -       if (!is_gimple_reg_type (TREE_TYPE (rhs)))
> -         continue;
> -
> -       vce = false;
> -       t = rhs;
> -       while (handled_component_p (t))
> -         {
> -           /* V_C_E can do things like convert an array of integers to one
> -                bigger integer and similar things we do not handle below.  */
> -             if (TREE_CODE (rhs) == VIEW_CONVERT_EXPR)
> -             {
> -               vce = true;
> -               break;
> -             }
> -           t = TREE_OPERAND (t, 0);
> -         }
> -       if (vce)
> -         continue;
>
> !       if (!ipa_load_from_parm_agg_1 (descriptors, parms_ainfo, stmt,
> !                                      rhs, &index, &offset, &size, &by_ref))
> !         continue;
> !       for (v = aggval; v; v = v->next)
> !         if (v->index == index
> !             && v->offset == offset)
> !           break;
> !       if (!v
> !           || v->by_ref != by_ref
> !           || tree_to_shwi (TYPE_SIZE (TREE_TYPE (v->value))) != size)
> !         continue;
>
> !       gcc_checking_assert (is_gimple_ip_invariant (v->value));
> !       if (!useless_type_conversion_p (TREE_TYPE (rhs), TREE_TYPE (v->value)))
> !         {
> !           if (fold_convertible_p (TREE_TYPE (rhs), v->value))
> !             val = fold_build1 (NOP_EXPR, TREE_TYPE (rhs), v->value);
> !           else if (TYPE_SIZE (TREE_TYPE (rhs))
> !                    == TYPE_SIZE (TREE_TYPE (v->value)))
> !             val = fold_build1 (VIEW_CONVERT_EXPR, TREE_TYPE (rhs), v->value);
> !           else
> !             {
> !               if (dump_file)
> !                 {
> !                   fprintf (dump_file, "    const ");
> !                   print_generic_expr (dump_file, v->value, 0);
> !                   fprintf (dump_file, "  can't be converted to type of ");
> !                   print_generic_expr (dump_file, rhs, 0);
> !                   fprintf (dump_file, "\n");
> !                 }
> !               continue;
> !             }
> !         }
> !       else
> !         val = v->value;
> !
> !       if (dump_file && (dump_flags & TDF_DETAILS))
> !         {
> !           fprintf (dump_file, "Modifying stmt:\n  ");
> !           print_gimple_stmt (dump_file, stmt, 0, 0);
> !         }
> !       gimple_assign_set_rhs_from_tree (&gsi, val);
> !       update_stmt (stmt);
> !
> !       if (dump_file && (dump_flags & TDF_DETAILS))
> !         {
> !           fprintf (dump_file, "into:\n  ");
> !           print_gimple_stmt (dump_file, stmt, 0, 0);
> !           fprintf (dump_file, "\n");
> !         }
> !
> !       something_changed = true;
> !       if (maybe_clean_eh_stmt (stmt)
> !           && gimple_purge_dead_eh_edges (gimple_bb (stmt)))
> !         cfg_changed = true;
> !       }
>
>     (*ipa_node_agg_replacements)[node->uid] = NULL;
> -   free_parms_ainfo (parms_ainfo, param_count);
>     descriptors.release ();
>
>     if (!something_changed)
> --- 5120,5146 ----
>     adjust_agg_replacement_values (node, aggval);
>     if (dump_file)
>       ipa_dump_agg_replacement_values (dump_file, aggval);
>
> !   fbi.node = node;
> !   fbi.info = NULL;
> !   fbi.ibbis = vNULL;
> !   fbi.ibbis.safe_grow_cleared (last_basic_block_for_fn (cfun));
> !   fbi.param_count = param_count;
> !   fbi.aa_walked = 0;
>
> !   descriptors.safe_grow_cleared (param_count);
> !   ipa_populate_param_decls (node, descriptors);
> !   calculate_dominance_info (CDI_DOMINATORS);
> !   ipcp_modif_dom_walker (&fbi, descriptors, aggval, &something_changed,
> !                        &cfg_changed).walk (ENTRY_BLOCK_PTR_FOR_FN (cfun));
>
> +   int i;
> +   struct ipa_bb_info *bi;
> +   FOR_EACH_VEC_ELT (fbi.ibbis, i, bi)
> +     free_ipa_bb_info (bi);
> +   fbi.ibbis.release ();
> +   free_dominance_info (CDI_DOMINATORS);
>     (*ipa_node_agg_replacements)[node->uid] = NULL;
>     descriptors.release ();
>
>     if (!something_changed)
> Index: src/gcc/ipa-prop.h
> ===================================================================
> *** src.orig/gcc/ipa-prop.h
> --- src/gcc/ipa-prop.h
> *************** struct ipa_node_params
> *** 371,378 ****
>     /* If this node is an ipa-cp clone, these are the known values that describe
>        what it has been specialized for.  */
>     vec<tree> known_vals;
> !   /* Whether the param uses analysis has already been performed.  */
> !   unsigned uses_analysis_done : 1;
>     /* Whether the function is enqueued in ipa-cp propagation stack.  */
>     unsigned node_enqueued : 1;
>     /* Whether we should create a specialized version based on values that are
> --- 371,379 ----
>     /* If this node is an ipa-cp clone, these are the known values that describe
>        what it has been specialized for.  */
>     vec<tree> known_vals;
> !   /* Whether the param uses analysis and jump function computation has already
> !      been performed.  */
> !   unsigned analysis_done : 1;
>     /* Whether the function is enqueued in ipa-cp propagation stack.  */
>     unsigned node_enqueued : 1;
>     /* Whether we should create a specialized version based on values that are
> Index: src/gcc/params.def
> ===================================================================
> *** src.orig/gcc/params.def
> --- src/gcc/params.def
> *************** DEFPARAM (PARAM_IPA_MAX_AGG_ITEMS,
> *** 947,952 ****
> --- 947,958 ----
>           "jump functions and lattices",
>           16, 0, 0)
>
> + DEFPARAM (PARAM_IPA_MAX_AA_STEPS,
> +         "ipa-max-aa-steps",
> +         "Maximum number of statements that will be visited by IPA formal "
> +         "parameter analysis based on alias analysis in any given function",
> +         100000, 0, 0)
> +
>   DEFPARAM (PARAM_IPA_CP_LOOP_HINT_BONUS,
>           "ipa-cp-loop-hint-bonus",
>           "Compile-time bonus IPA-CP assigns to candidates which make loop "
>

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH] Make ipa-prop analyze BBs in DOM order
  2014-04-28  9:05 ` Richard Biener
@ 2014-04-28 10:06   ` Martin Jambor
  2014-04-28 11:44     ` Richard Biener
  0 siblings, 1 reply; 5+ messages in thread
From: Martin Jambor @ 2014-04-28 10:06 UTC (permalink / raw)
  To: Richard Biener; +Cc: GCC Patches, Jan Hubicka

Hi,

On Mon, Apr 28, 2014 at 11:01:45AM +0200, Richard Biener wrote:
> On Fri, Apr 25, 2014 at 5:12 PM, Martin Jambor <mjambor@suse.cz> wrote:
> > Hi,
> >
> > the following patch deals with requested propagation in PR 53787 in
> > the real benchmark (as opposed to the original simple testcase) by
> > analyzing individual BBs in ipa-prop.c in dominator order.
> >
> > Currently we do the analysis in two loops, in the first the order is
> > given by FOR_EACH_BB_FN and in the second the order is the order of
> > call graph edges (which in practice is quite bad because we tend to
> > start with BBs towards the end).  When analysis determines that a
> > non-SSA parameter or that data pointed to by a parameter are modified,
> > this is marked into a function wide flag (describing the parameter)
> > and we always consider the data clobbered from that moment on in order
> > to save AA walking.
> >
> > This patch changes the analysis into dominator order and data is
> > considered clobbered only in dominator children of a block where it
> > was determined to be possibly clobbered, not in the whole function.
> > This was confirmed to help in the aforementioned PR.
> >
> > The patch also, enforces a cap on the number of statements walked
> > (approx. 4 times the highest I have ever seen).  On the other hand it
> > gives up trying to cache the bitmap of visited memory-SSAs.  The
> > per-BB information had to be put somewhere and I took this opportunity
> > to cram a lot of commonly used per-function data into the same
> > structure, which is then passed among various functions.  The new
> > structure replaces the struct param_analysis_info.
> >
> > Bootstrapped and tested on x86_64-linux, I have also LTO-built Firefox
> > at -O3 with it.  OK for trunk?
> 
> 100000 is a very big number - is that a count for the whole program?

The limit is per function.  I thought I lost my measurements but today
I have found them.  Apparently the highest number of visited
definitions I have measured was 13689 in algnci.fppized.f (from
something in SpecFP 2006) and that was a big outlier (e.g. the biggest
number during bootstrap was 3798 in insn-attrtab.c).  I'm sorry I
misremembered the record, I really thought it was over 20 thousand.
I'll lower the limit to 50000 then.  Or even 25000 if that is
considered too big but the limit is really intended to guard against
pathological cases.

> Did you make sure to excercise the fallback path by for example
> bootstrapping or building firefox with a much lower number (say, 1)?

I didn't but...

> 
> Walking all immediate dominators as fallback possibly visits
> on the order of O (n_basic_blocks) blocks, so it isn't really "fast".
> It's surely faster than doing the oracle walk, but can't we have a
> quicker fallback (like fail?)

...the fallback is to fail (see all calls to aa_overwalked).
I.e. when the limit is reached, from that moment on, all memory is
considered clobbered and no AA is performed on that function as a part
of ipa_analyze_node or IPA-CP transformation phase.  It is the
analysis itself that is done in DOM order (as opposed to the order of
call graph edges) and once AA fails in a BB, we remember not to bother
with that parameter in all DOM children, regardless of the cap.

Still potentially problematic are callers in ipa-inline-analysis.c but
they have always been, we have never had any guards there.  Making
them adhere to these limits means that IPA-CP and ipa-inline need to
share struct func_body_info during the analysis stage so it requires
some coordination with Honza.  This will also increase the chance of
hitting the limit, of course :-)

Martin

> 
> Thanks,
> Richard.
> 
> > Thanks,
> >
> > Martin
> >
> >
> > 2014-02-12  Martin Jambor  <mjambor@suse.cz>
> >
> >         PR tree-optimization/53787
> >         * params.def (PARAM_IPA_CP_LOOP_HINT_BONUS): New param.
> >         * ipa-prop.h (ipa_node_params): Rename uses_analysis_done to
> >         analysis_done, update all uses.
> >         * ipa-prop.c: Include domwalk.h
> >         (param_analysis_info): Removed.
> >         (param_aa_status): New type.
> >         (ipa_bb_info): Likewise.
> >         (func_body_info): Likewise.
> >         (ipa_get_bb_info): New function.
> >         (aa_overwalked): Likewise.
> >         (find_dominating_aa_status): Likewise.
> >         (parm_bb_aa_status_for_bb): Likewise.
> >         (parm_preserved_before_stmt_p): Changed to use new param AA info.
> >         (load_from_unmodified_param): Accept func_body_info as a parameter
> >         instead of parms_ainfo.
> >         (parm_ref_data_preserved_p): Changed to use new param AA info.
> >         (parm_ref_data_pass_through_p): Likewise.
> >         (ipa_load_from_parm_agg_1): Likewise.  Update callers.
> >         (compute_complex_assign_jump_func): Changed to use new param AA info.
> >         (compute_complex_ancestor_jump_func): Likewise.
> >         (ipa_compute_jump_functions_for_edge): Likewise.
> >         (ipa_compute_jump_functions): Removed.
> >         (ipa_compute_jump_functions_for_bb): New function.
> >         (ipa_analyze_indirect_call_uses): Likewise, moved variable
> >         declarations down.
> >         (ipa_analyze_virtual_call_uses): Accept func_body_info instead of node
> >         and info, moved variable declarations down.
> >         (ipa_analyze_call_uses): Accept and pass on func_body_info instead of
> >         node and info.
> >         (ipa_analyze_stmt_uses): Likewise.
> >         (ipa_analyze_params_uses): Removed.
> >         (ipa_analyze_params_uses_in_bb): New function.
> >         (ipa_analyze_controlled_uses): Likewise.
> >         (free_ipa_bb_info): Likewise.
> >         (analysis_dom_walker): New class.
> >         (ipa_analyze_node): Handle node-specific forbidden analysis,
> >         initialize and free func_body_info, use dominator walker.
> >         (ipcp_modif_dom_walker): New class.
> >         (ipcp_transform_function): Create and free func_body_info, use
> >         ipcp_modif_dom_walker, moved a lot of functionality there.
> >
> > Index: src/gcc/ipa-prop.c
> > ===================================================================
> > *** src.orig/gcc/ipa-prop.c
> > --- src/gcc/ipa-prop.c
> > *************** along with GCC; see the file COPYING3.
> > *** 59,72 ****
> >   #include "ipa-utils.h"
> >   #include "stringpool.h"
> >   #include "tree-ssanames.h"
> >
> > ! /* Intermediate information about a parameter that is only useful during the
> > !    run of ipa_analyze_node and is not kept afterwards.  */
> >
> > ! struct param_analysis_info
> >   {
> >     bool parm_modified, ref_modified, pt_modified;
> > !   bitmap parm_visited_statements, pt_visited_statements;
> >   };
> >
> >   /* Vector where the parameter infos are actually stored. */
> > --- 59,111 ----
> >   #include "ipa-utils.h"
> >   #include "stringpool.h"
> >   #include "tree-ssanames.h"
> > + #include "domwalk.h"
> >
> > ! /* Intermediate information that we get from AA analysis about a parameter.  */
> >
> > ! struct param_aa_status
> >   {
> > +   /* If not true, look at the dominator parent instead.  */
> > +   bool valid;
> > +
> > +   /* Whether we have seen something which might have modified the data in
> > +      question.  Parm is for the parameter itself, ref is for data it points to
> > +      but using the alias type of individual accesses and pt is the same thing
> > +      but for computing aggregate pass-through functions using a very inclusive
> > +      ao_ref.  */
> >     bool parm_modified, ref_modified, pt_modified;
> > ! };
> > !
> > ! /* Information related to a given BB that used only when looking at function
> > !    body.  */
> > !
> > ! struct ipa_bb_info
> > ! {
> > !   /* Call graph edges going out of this BB.  */
> > !   vec<cgraph_edge_p> cg_edges;
> > !   /* Alias analysis statuses of each formal parameter at this bb.  */
> > !   vec<param_aa_status> paas;
> > ! };
> > !
> > ! /* Structure with global information that is only used when looking at function
> > !    body. */
> > !
> > ! struct func_body_info
> > ! {
> > !   /* The node that is being analyzed.  */
> > !   cgraph_node *node;
> > !
> > !   /* Its info.  */
> > !   struct ipa_node_params *info;
> > !
> > !   /* Information about individual BBs. */
> > !   vec<ipa_bb_info> ibbis;
> > !
> > !   /* Number of parameters.  */
> > !   int param_count;
> > !
> > !   /* Number of statements already walked by when analyzing this function.  */
> > !   unsigned int aa_walked;
> >   };
> >
> >   /* Vector where the parameter infos are actually stored. */
> > *************** ipa_binfo_from_known_type_jfunc (struct
> > *** 510,515 ****
> > --- 549,564 ----
> >                               jfunc->value.known_type.component_type);
> >   }
> >
> > + /* Get IPA BB information about the given BB.  FBI is the context of analyzis
> > +    of this function body.  */
> > +
> > + static struct ipa_bb_info *
> > + ipa_get_bb_info (struct func_body_info *fbi, basic_block bb)
> > + {
> > +   gcc_checking_assert (fbi);
> > +   return &fbi->ibbis[bb->index];
> > + }
> > +
> >   /* Structure to be passed in between detect_type_change and
> >      check_stmt_for_type_change.  */
> >
> > *************** mark_modified (ao_ref *ao ATTRIBUTE_UNUS
> > *** 769,802 ****
> >     return true;
> >   }
> >
> >   /* Return true if a load from a formal parameter PARM_LOAD is known to retrieve
> >      a value known not to be modified in this function before reaching the
> > !    statement STMT.  PARM_AINFO is a pointer to a structure containing temporary
> > !    information about the parameter.  */
> >
> >   static bool
> > ! parm_preserved_before_stmt_p (struct param_analysis_info *parm_ainfo,
> > !                              gimple stmt, tree parm_load)
> >   {
> >     bool modified = false;
> > -   bitmap *visited_stmts;
> >     ao_ref refd;
> >
> > !   if (parm_ainfo && parm_ainfo->parm_modified)
> > !     return false;
> >
> >     gcc_checking_assert (gimple_vuse (stmt) != NULL_TREE);
> >     ao_ref_init (&refd, parm_load);
> > !   /* We can cache visited statements only when parm_ainfo is available and when
> > !      we are looking at a naked load of the whole parameter.  */
> > !   if (!parm_ainfo || TREE_CODE (parm_load) != PARM_DECL)
> > !     visited_stmts = NULL;
> > !   else
> > !     visited_stmts = &parm_ainfo->parm_visited_statements;
> > !   walk_aliased_vdefs (&refd, gimple_vuse (stmt), mark_modified, &modified,
> > !                     visited_stmts);
> > !   if (parm_ainfo && modified)
> > !     parm_ainfo->parm_modified = true;
> >     return !modified;
> >   }
> >
> > --- 818,918 ----
> >     return true;
> >   }
> >
> > + /* Return true if we have already walked so many statements in AA that we
> > +    should really just start giving up.  */
> > +
> > + static bool
> > + aa_overwalked (struct func_body_info *fbi)
> > + {
> > +   gcc_checking_assert (fbi);
> > +   return fbi->aa_walked > (unsigned) PARAM_VALUE (PARAM_IPA_MAX_AA_STEPS);
> > + }
> > +
> > + /* Find the nearest valid aa status for parameter specified by INDEX that
> > +    dominates BB.  */
> > +
> > + static struct param_aa_status *
> > + find_dominating_aa_status (struct func_body_info *fbi, basic_block bb,
> > +                          int index)
> > + {
> > +   while (true)
> > +     {
> > +       bb = get_immediate_dominator (CDI_DOMINATORS, bb);
> > +       if (!bb)
> > +       return NULL;
> > +       struct ipa_bb_info *bi = ipa_get_bb_info (fbi, bb);
> > +       if (!bi->paas.is_empty ()
> > +         && bi->paas[index].valid)
> > +       return &bi->paas[index];
> > +     }
> > + }
> > +
> > + /* Get AA status structure for the given BB and parameter with INDEX.  Allocate
> > +    structures and/or intialize the result with a dominating description as
> > +    necessary.  */
> > +
> > + static struct param_aa_status *
> > + parm_bb_aa_status_for_bb (struct func_body_info *fbi, basic_block bb,
> > +                         int index)
> > + {
> > +   gcc_checking_assert (fbi);
> > +   struct ipa_bb_info *bi = ipa_get_bb_info (fbi, bb);
> > +   if (bi->paas.is_empty ())
> > +     bi->paas.safe_grow_cleared (fbi->param_count);
> > +   struct param_aa_status *paa = &bi->paas[index];
> > +   if (!paa->valid)
> > +     {
> > +       gcc_checking_assert (!paa->parm_modified
> > +                          && !paa->ref_modified
> > +                          && !paa->pt_modified);
> > +       struct param_aa_status *dom_paa;
> > +       dom_paa = find_dominating_aa_status (fbi, bb, index);
> > +       if (dom_paa)
> > +       *paa = *dom_paa;
> > +       else
> > +       paa->valid = true;
> > +     }
> > +
> > +   return paa;
> > + }
> > +
> >   /* Return true if a load from a formal parameter PARM_LOAD is known to retrieve
> >      a value known not to be modified in this function before reaching the
> > !    statement STMT.  FBI holds information about the function we have so far
> > !    gathered but do not survive the summary building stage.  */
> >
> >   static bool
> > ! parm_preserved_before_stmt_p (struct func_body_info *fbi, int index,
> > !                             gimple stmt, tree parm_load)
> >   {
> > +   struct param_aa_status *paa;
> >     bool modified = false;
> >     ao_ref refd;
> >
> > !   /* FIXME: FBI can be NULL if we are being called from outside
> > !      ipa_node_analysis or ipcp_transform_function, which currently happens
> > !      during inlining analysis.  It would be great to extend fbi's lifetime and
> > !      always have it.  Currently, we are just not afraid of too much walking in
> > !      that case.  */
> > !   if (fbi)
> > !     {
> > !       if (aa_overwalked (fbi))
> > !       return false;
> > !       paa = parm_bb_aa_status_for_bb (fbi, gimple_bb (stmt), index);
> > !       if (paa->parm_modified)
> > !       return false;
> > !     }
> > !   else
> > !     paa = NULL;
> >
> >     gcc_checking_assert (gimple_vuse (stmt) != NULL_TREE);
> >     ao_ref_init (&refd, parm_load);
> > !   int walked = walk_aliased_vdefs (&refd, gimple_vuse (stmt), mark_modified,
> > !                                  &modified, NULL);
> > !   if (fbi)
> > !     fbi->aa_walked += walked;
> > !   if (paa && modified)
> > !     paa->parm_modified = true;
> >     return !modified;
> >   }
> >
> > *************** parm_preserved_before_stmt_p (struct par
> > *** 805,812 ****
> >      modified.  Otherwise return -1.  */
> >
> >   static int
> > ! load_from_unmodified_param (vec<ipa_param_descriptor> descriptors,
> > !                           struct param_analysis_info *parms_ainfo,
> >                             gimple stmt)
> >   {
> >     int index;
> > --- 921,928 ----
> >      modified.  Otherwise return -1.  */
> >
> >   static int
> > ! load_from_unmodified_param (struct func_body_info *fbi,
> > !                           vec<ipa_param_descriptor> descriptors,
> >                             gimple stmt)
> >   {
> >     int index;
> > *************** load_from_unmodified_param (vec<ipa_para
> > *** 821,865 ****
> >
> >     index = ipa_get_param_decl_index_1 (descriptors, op1);
> >     if (index < 0
> > !       || !parm_preserved_before_stmt_p (parms_ainfo ? &parms_ainfo[index]
> > !                                       : NULL, stmt, op1))
> >       return -1;
> >
> >     return index;
> >   }
> >
> > ! /* Return true if memory reference REF loads data that are known to be
> > !    unmodified in this function before reaching statement STMT.  PARM_AINFO, if
> > !    non-NULL, is a pointer to a structure containing temporary information about
> > !    PARM.  */
> >
> >   static bool
> > ! parm_ref_data_preserved_p (struct param_analysis_info *parm_ainfo,
> > !                             gimple stmt, tree ref)
> >   {
> >     bool modified = false;
> >     ao_ref refd;
> >
> > !   gcc_checking_assert (gimple_vuse (stmt));
> > !   if (parm_ainfo && parm_ainfo->ref_modified)
> > !     return false;
> >
> >     ao_ref_init (&refd, ref);
> > !   walk_aliased_vdefs (&refd, gimple_vuse (stmt), mark_modified, &modified,
> > !                     NULL);
> > !   if (parm_ainfo && modified)
> > !     parm_ainfo->ref_modified = true;
> >     return !modified;
> >   }
> >
> > ! /* Return true if the data pointed to by PARM is known to be unmodified in this
> > !    function before reaching call statement CALL into which it is passed.
> > !    PARM_AINFO is a pointer to a structure containing temporary information
> > !    about PARM.  */
> >
> >   static bool
> > ! parm_ref_data_pass_through_p (struct param_analysis_info *parm_ainfo,
> > !                              gimple call, tree parm)
> >   {
> >     bool modified = false;
> >     ao_ref refd;
> > --- 937,995 ----
> >
> >     index = ipa_get_param_decl_index_1 (descriptors, op1);
> >     if (index < 0
> > !       || !parm_preserved_before_stmt_p (fbi, index, stmt, op1))
> >       return -1;
> >
> >     return index;
> >   }
> >
> > ! /* Return true if memory reference REF (which must be a load through parameter
> > !    with INDEX) loads data that are known to be unmodified in this function
> > !    before reaching statement STMT.  */
> >
> >   static bool
> > ! parm_ref_data_preserved_p (struct func_body_info *fbi,
> > !                          int index, gimple stmt, tree ref)
> >   {
> > +   struct param_aa_status *paa;
> >     bool modified = false;
> >     ao_ref refd;
> >
> > !   /* FIXME: FBI can be NULL if we are being called from outside
> > !      ipa_node_analysis or ipcp_transform_function, which currently happens
> > !      during inlining analysis.  It would be great to extend fbi's lifetime and
> > !      always have it.  Currently, we are just not afraid of too much walking in
> > !      that case.  */
> > !   if (fbi)
> > !     {
> > !       if (aa_overwalked (fbi))
> > !       return false;
> > !       paa = parm_bb_aa_status_for_bb (fbi, gimple_bb (stmt), index);
> > !       if (paa->ref_modified)
> > !       return false;
> > !     }
> > !   else
> > !     paa = NULL;
> >
> > +   gcc_checking_assert (gimple_vuse (stmt));
> >     ao_ref_init (&refd, ref);
> > !   int walked = walk_aliased_vdefs (&refd, gimple_vuse (stmt), mark_modified,
> > !                                  &modified, NULL);
> > !   if (fbi)
> > !     fbi->aa_walked += walked;
> > !   if (paa && modified)
> > !     paa->ref_modified = true;
> >     return !modified;
> >   }
> >
> > ! /* Return true if the data pointed to by PARM (which is a parameter with INDEX)
> > !    is known to be unmodified in this function before reaching call statement
> > !    CALL into which it is passed.  PARM_AINFO is a pointer to a structure
> > !    containing temporary information about PARM.  */
> >
> >   static bool
> > ! parm_ref_data_pass_through_p (struct func_body_info *fbi, int index,
> > !                             gimple call, tree parm)
> >   {
> >     bool modified = false;
> >     ao_ref refd;
> > *************** parm_ref_data_pass_through_p (struct par
> > *** 868,884 ****
> >        function because it is not goin to use it.  But do not cache the result
> >        either.  Also, no such calculations for non-pointers.  */
> >     if (!gimple_vuse (call)
> > !       || !POINTER_TYPE_P (TREE_TYPE (parm)))
> >       return false;
> >
> > !   if (parm_ainfo->pt_modified)
> >       return false;
> >
> >     ao_ref_init_from_ptr_and_size (&refd, parm, NULL_TREE);
> > !   walk_aliased_vdefs (&refd, gimple_vuse (call), mark_modified, &modified,
> > !                     parm_ainfo ? &parm_ainfo->pt_visited_statements : NULL);
> >     if (modified)
> > !     parm_ainfo->pt_modified = true;
> >     return !modified;
> >   }
> >
> > --- 998,1018 ----
> >        function because it is not goin to use it.  But do not cache the result
> >        either.  Also, no such calculations for non-pointers.  */
> >     if (!gimple_vuse (call)
> > !       || !POINTER_TYPE_P (TREE_TYPE (parm))
> > !       || aa_overwalked (fbi))
> >       return false;
> >
> > !   struct param_aa_status *paa = parm_bb_aa_status_for_bb (fbi, gimple_bb (call),
> > !                                                         index);
> > !   if (paa->pt_modified)
> >       return false;
> >
> >     ao_ref_init_from_ptr_and_size (&refd, parm, NULL_TREE);
> > !   int walked = walk_aliased_vdefs (&refd, gimple_vuse (call), mark_modified,
> > !                                  &modified, NULL);
> > !   fbi->aa_walked += walked;
> >     if (modified)
> > !     paa->pt_modified = true;
> >     return !modified;
> >   }
> >
> > *************** parm_ref_data_pass_through_p (struct par
> > *** 893,902 ****
> >      reference respectively.  */
> >
> >   static bool
> > ! ipa_load_from_parm_agg_1 (vec<ipa_param_descriptor> descriptors,
> > !                         struct param_analysis_info *parms_ainfo, gimple stmt,
> > !                         tree op, int *index_p, HOST_WIDE_INT *offset_p,
> > !                         HOST_WIDE_INT *size_p, bool *by_ref_p)
> >   {
> >     int index;
> >     HOST_WIDE_INT size, max_size;
> > --- 1027,1037 ----
> >      reference respectively.  */
> >
> >   static bool
> > ! ipa_load_from_parm_agg_1 (struct func_body_info *fbi,
> > !                         vec<ipa_param_descriptor> descriptors,
> > !                         gimple stmt, tree op, int *index_p,
> > !                         HOST_WIDE_INT *offset_p, HOST_WIDE_INT *size_p,
> > !                         bool *by_ref_p)
> >   {
> >     int index;
> >     HOST_WIDE_INT size, max_size;
> > *************** ipa_load_from_parm_agg_1 (vec<ipa_param_
> > *** 909,916 ****
> >       {
> >         int index = ipa_get_param_decl_index_1 (descriptors, base);
> >         if (index >= 0
> > !         && parm_preserved_before_stmt_p (parms_ainfo ? &parms_ainfo[index]
> > !                                          : NULL, stmt, op))
> >         {
> >           *index_p = index;
> >           *by_ref_p = false;
> > --- 1044,1050 ----
> >       {
> >         int index = ipa_get_param_decl_index_1 (descriptors, base);
> >         if (index >= 0
> > !         && parm_preserved_before_stmt_p (fbi, index, stmt, op))
> >         {
> >           *index_p = index;
> >           *by_ref_p = false;
> > *************** ipa_load_from_parm_agg_1 (vec<ipa_param_
> > *** 949,960 ****
> >         */
> >
> >         gimple def = SSA_NAME_DEF_STMT (TREE_OPERAND (base, 0));
> > !       index = load_from_unmodified_param (descriptors, parms_ainfo, def);
> >       }
> >
> >     if (index >= 0
> > !       && parm_ref_data_preserved_p (parms_ainfo ? &parms_ainfo[index] : NULL,
> > !                                   stmt, op))
> >       {
> >         *index_p = index;
> >         *by_ref_p = true;
> > --- 1083,1093 ----
> >         */
> >
> >         gimple def = SSA_NAME_DEF_STMT (TREE_OPERAND (base, 0));
> > !       index = load_from_unmodified_param (fbi, descriptors, def);
> >       }
> >
> >     if (index >= 0
> > !       && parm_ref_data_preserved_p (fbi, index, stmt, op))
> >       {
> >         *index_p = index;
> >         *by_ref_p = true;
> > *************** ipa_load_from_parm_agg (struct ipa_node_
> > *** 973,979 ****
> >                         tree op, int *index_p, HOST_WIDE_INT *offset_p,
> >                         bool *by_ref_p)
> >   {
> > !   return ipa_load_from_parm_agg_1 (info->descriptors, NULL, stmt, op, index_p,
> >                                    offset_p, NULL, by_ref_p);
> >   }
> >
> > --- 1106,1112 ----
> >                         tree op, int *index_p, HOST_WIDE_INT *offset_p,
> >                         bool *by_ref_p)
> >   {
> > !   return ipa_load_from_parm_agg_1 (NULL, info->descriptors, stmt, op, index_p,
> >                                    offset_p, NULL, by_ref_p);
> >   }
> >
> > *************** ipa_load_from_parm_agg (struct ipa_node_
> > *** 1031,1038 ****
> >      only needed for intraprocedural analysis.  */
> >
> >   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,
> >                                   tree param_type)
> > --- 1164,1171 ----
> >      only needed for intraprocedural analysis.  */
> >
> >   static void
> > ! compute_complex_assign_jump_func (struct func_body_info *fbi,
> > !                                 struct ipa_node_params *info,
> >                                   struct ipa_jump_func *jfunc,
> >                                   gimple call, gimple stmt, tree name,
> >                                   tree param_type)
> > *************** compute_complex_assign_jump_func (struct
> > *** 1048,1060 ****
> >         if (SSA_NAME_IS_DEFAULT_DEF (op1))
> >         index = ipa_get_param_decl_index (info, SSA_NAME_VAR (op1));
> >         else
> > !       index = load_from_unmodified_param (info->descriptors, parms_ainfo,
> >                                             SSA_NAME_DEF_STMT (op1));
> >         tc_ssa = op1;
> >       }
> >     else
> >       {
> > !       index = load_from_unmodified_param (info->descriptors, parms_ainfo, stmt);
> >         tc_ssa = gimple_assign_lhs (stmt);
> >       }
> >
> > --- 1181,1193 ----
> >         if (SSA_NAME_IS_DEFAULT_DEF (op1))
> >         index = ipa_get_param_decl_index (info, SSA_NAME_VAR (op1));
> >         else
> > !       index = load_from_unmodified_param (fbi, info->descriptors,
> >                                             SSA_NAME_DEF_STMT (op1));
> >         tc_ssa = op1;
> >       }
> >     else
> >       {
> > !       index = load_from_unmodified_param (fbi, info->descriptors, stmt);
> >         tc_ssa = gimple_assign_lhs (stmt);
> >       }
> >
> > *************** compute_complex_assign_jump_func (struct
> > *** 1075,1082 ****
> >         }
> >         else if (gimple_assign_single_p (stmt))
> >         {
> > !         bool agg_p = parm_ref_data_pass_through_p (&parms_ainfo[index],
> > !                                                    call, tc_ssa);
> >           bool type_p = false;
> >
> >           if (param_type && POINTER_TYPE_P (param_type))
> > --- 1208,1214 ----
> >         }
> >         else if (gimple_assign_single_p (stmt))
> >         {
> > !         bool agg_p = parm_ref_data_pass_through_p (fbi, index, call, tc_ssa);
> >           bool type_p = false;
> >
> >           if (param_type && POINTER_TYPE_P (param_type))
> > *************** compute_complex_assign_jump_func (struct
> > *** 1115,1121 ****
> >         if (type_p || jfunc->type == IPA_JF_UNKNOWN)
> >         ipa_set_ancestor_jf (jfunc, offset,
> >                              type_p ? TREE_TYPE (param_type) : NULL, index,
> > !                            parm_ref_data_pass_through_p (&parms_ainfo[index],
> >                                                            call, ssa), type_p);
> >       }
> >   }
> > --- 1247,1253 ----
> >         if (type_p || jfunc->type == IPA_JF_UNKNOWN)
> >         ipa_set_ancestor_jf (jfunc, offset,
> >                              type_p ? TREE_TYPE (param_type) : NULL, index,
> > !                            parm_ref_data_pass_through_p (fbi, index,
> >                                                            call, ssa), type_p);
> >       }
> >   }
> > *************** get_ancestor_addr_info (gimple assign, t
> > *** 1187,1194 ****
> >        return D.1879_6;  */
> >
> >   static void
> > ! compute_complex_ancestor_jump_func (struct ipa_node_params *info,
> > !                                   struct param_analysis_info *parms_ainfo,
> >                                     struct ipa_jump_func *jfunc,
> >                                     gimple call, gimple phi, tree param_type)
> >   {
> > --- 1319,1326 ----
> >        return D.1879_6;  */
> >
> >   static void
> > ! compute_complex_ancestor_jump_func (struct func_body_info *fbi,
> > !                                   struct ipa_node_params *info,
> >                                     struct ipa_jump_func *jfunc,
> >                                     gimple call, gimple phi, tree param_type)
> >   {
> > *************** compute_complex_ancestor_jump_func (stru
> > *** 1247,1255 ****
> >       type_p = !detect_type_change (obj, expr, TREE_TYPE (param_type),
> >                                   call, jfunc, offset);
> >     if (type_p || jfunc->type == IPA_JF_UNKNOWN)
> > !     ipa_set_ancestor_jf (jfunc, offset, type_p ? TREE_TYPE (param_type) : NULL, index,
> > !                        parm_ref_data_pass_through_p (&parms_ainfo[index],
> > !                                                      call, parm), type_p);
> >   }
> >
> >   /* Given OP which is passed as an actual argument to a called function,
> > --- 1379,1388 ----
> >       type_p = !detect_type_change (obj, expr, TREE_TYPE (param_type),
> >                                   call, jfunc, offset);
> >     if (type_p || jfunc->type == IPA_JF_UNKNOWN)
> > !     ipa_set_ancestor_jf (jfunc, offset, type_p ? TREE_TYPE (param_type) : NULL,
> > !                        index,
> > !                        parm_ref_data_pass_through_p (fbi, index, call, parm),
> > !                        type_p);
> >   }
> >
> >   /* Given OP which is passed as an actual argument to a called function,
> > *************** ipa_get_callee_param_type (struct cgraph
> > *** 1594,1600 ****
> >      to this callsite.  */
> >
> >   static void
> > ! 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);
> > --- 1727,1733 ----
> >      to this callsite.  */
> >
> >   static void
> > ! ipa_compute_jump_functions_for_edge (struct func_body_info *fbi,
> >                                      struct cgraph_edge *cs)
> >   {
> >     struct ipa_node_params *info = IPA_NODE_REF (cs->caller);
> > *************** ipa_compute_jump_functions_for_edge (str
> > *** 1628,1634 ****
> >           /* Aggregate passed by value, check for pass-through, otherwise we
> >              will attempt to fill in aggregate contents later in this
> >              for cycle.  */
> > !         if (parm_preserved_before_stmt_p (&parms_ainfo[index], call, arg))
> >             {
> >               ipa_set_jf_simple_pass_through (jfunc, index, false, false);
> >               continue;
> > --- 1761,1767 ----
> >           /* Aggregate passed by value, check for pass-through, otherwise we
> >              will attempt to fill in aggregate contents later in this
> >              for cycle.  */
> > !         if (parm_preserved_before_stmt_p (fbi, index, call, arg))
> >             {
> >               ipa_set_jf_simple_pass_through (jfunc, index, false, false);
> >               continue;
> > *************** ipa_compute_jump_functions_for_edge (str
> > *** 1642,1649 ****
> >               if (index >= 0)
> >                 {
> >                   bool agg_p, type_p;
> > !                 agg_p = parm_ref_data_pass_through_p (&parms_ainfo[index],
> > !                                                       call, arg);
> >                   if (param_type && POINTER_TYPE_P (param_type))
> >                     type_p = !detect_type_change_ssa (arg, TREE_TYPE (param_type),
> >                                                       call, jfunc);
> > --- 1775,1781 ----
> >               if (index >= 0)
> >                 {
> >                   bool agg_p, type_p;
> > !                 agg_p = parm_ref_data_pass_through_p (fbi, index, call, arg);
> >                   if (param_type && POINTER_TYPE_P (param_type))
> >                     type_p = !detect_type_change_ssa (arg, TREE_TYPE (param_type),
> >                                                       call, jfunc);
> > *************** ipa_compute_jump_functions_for_edge (str
> > *** 1658,1667 ****
> >             {
> >               gimple stmt = SSA_NAME_DEF_STMT (arg);
> >               if (is_gimple_assign (stmt))
> > !               compute_complex_assign_jump_func (info, parms_ainfo, jfunc,
> >                                                   call, stmt, arg, param_type);
> >               else if (gimple_code (stmt) == GIMPLE_PHI)
> > !               compute_complex_ancestor_jump_func (info, parms_ainfo, jfunc,
> >                                                     call, stmt, param_type);
> >             }
> >         }
> > --- 1790,1799 ----
> >             {
> >               gimple stmt = SSA_NAME_DEF_STMT (arg);
> >               if (is_gimple_assign (stmt))
> > !               compute_complex_assign_jump_func (fbi, info, jfunc,
> >                                                   call, stmt, arg, param_type);
> >               else if (gimple_code (stmt) == GIMPLE_PHI)
> > !               compute_complex_ancestor_jump_func (fbi, info, jfunc,
> >                                                     call, stmt, param_type);
> >             }
> >         }
> > *************** ipa_compute_jump_functions_for_edge (str
> > *** 1692,1718 ****
> >   }
> >
> >   /* Compute jump functions for all edges - both direct and indirect - outgoing
> > !    from NODE.  Also count the actual arguments in the process.  */
> >
> >   static void
> > ! ipa_compute_jump_functions (struct cgraph_node *node,
> > !                           struct param_analysis_info *parms_ainfo)
> >   {
> >     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.  */
> > !       if (!callee->definition && !flag_lto)
> > !       continue;
> > !       ipa_compute_jump_functions_for_edge (parms_ainfo, cs);
> > !     }
> >
> > !   for (cs = node->indirect_calls; cs; cs = cs->next_callee)
> > !     ipa_compute_jump_functions_for_edge (parms_ainfo, cs);
> >   }
> >
> >   /* If STMT looks like a statement loading a value from a member pointer formal
> > --- 1824,1852 ----
> >   }
> >
> >   /* Compute jump functions for all edges - both direct and indirect - outgoing
> > !    from BB.  */
> >
> >   static void
> > ! ipa_compute_jump_functions_for_bb (struct func_body_info *fbi, basic_block bb)
> >   {
> > +   struct ipa_bb_info *bi = ipa_get_bb_info (fbi, bb);
> > +   int i;
> >     struct cgraph_edge *cs;
> >
> > !   FOR_EACH_VEC_ELT_REVERSE (bi->cg_edges, i, cs)
> >       {
> > !       struct cgraph_node *callee = cs->callee;
> >
> > !       if (callee)
> > !       {
> > !         cgraph_function_or_thunk_node (callee, NULL);
> > !         /* We do not need to bother analyzing calls to unknown functions
> > !            unless they may become known during lto/whopr.  */
> > !         if (!callee->definition && !flag_lto)
> > !           continue;
> > !       }
> > !       ipa_compute_jump_functions_for_edge (fbi, cs);
> > !     }
> >   }
> >
> >   /* If STMT looks like a statement loading a value from a member pointer formal
> > *************** ipa_note_param_call (struct cgraph_node
> > *** 1855,1891 ****
> >      passed by value or reference.  */
> >
> >   static void
> > ! ipa_analyze_indirect_call_uses (struct cgraph_node *node,
> > !                               struct ipa_node_params *info,
> > !                               struct param_analysis_info *parms_ainfo,
> > !                               gimple call, tree target)
> > ! {
> > !   gimple def;
> > !   tree n1, n2;
> > !   gimple d1, d2;
> > !   tree rec, rec2, cond;
> > !   gimple branch;
> > !   int index;
> > !   basic_block bb, virt_bb, join;
> >     HOST_WIDE_INT offset;
> >     bool by_ref;
> >
> >     if (SSA_NAME_IS_DEFAULT_DEF (target))
> >       {
> >         tree var = SSA_NAME_VAR (target);
> > !       index = ipa_get_param_decl_index (info, var);
> >         if (index >= 0)
> > !       ipa_note_param_call (node, index, call);
> >         return;
> >       }
> >
> > !   def = SSA_NAME_DEF_STMT (target);
> >     if (gimple_assign_single_p (def)
> > !       && ipa_load_from_parm_agg_1 (info->descriptors, parms_ainfo, def,
> >                                    gimple_assign_rhs1 (def), &index, &offset,
> >                                    NULL, &by_ref))
> >       {
> > !       struct cgraph_edge *cs = ipa_note_param_call (node, index, call);
> >         if (cs->indirect_info->offset != offset)
> >         cs->indirect_info->outer_type = NULL;
> >         cs->indirect_info->offset = offset;
> > --- 1989,2018 ----
> >      passed by value or reference.  */
> >
> >   static void
> > ! ipa_analyze_indirect_call_uses (struct func_body_info *fbi, gimple call,
> > !                               tree target)
> > ! {
> > !   struct ipa_node_params *info = fbi->info;
> >     HOST_WIDE_INT offset;
> >     bool by_ref;
> >
> >     if (SSA_NAME_IS_DEFAULT_DEF (target))
> >       {
> >         tree var = SSA_NAME_VAR (target);
> > !       int index = ipa_get_param_decl_index (info, var);
> >         if (index >= 0)
> > !       ipa_note_param_call (fbi->node, index, call);
> >         return;
> >       }
> >
> > !   int index;
> > !   gimple def = SSA_NAME_DEF_STMT (target);
> >     if (gimple_assign_single_p (def)
> > !       && ipa_load_from_parm_agg_1 (fbi, info->descriptors, def,
> >                                    gimple_assign_rhs1 (def), &index, &offset,
> >                                    NULL, &by_ref))
> >       {
> > !       struct cgraph_edge *cs = ipa_note_param_call (fbi->node, index, call);
> >         if (cs->indirect_info->offset != offset)
> >         cs->indirect_info->outer_type = NULL;
> >         cs->indirect_info->offset = offset;
> > *************** ipa_analyze_indirect_call_uses (struct c
> > *** 1904,1917 ****
> >
> >     /* First, we need to check whether one of these is a load from a member
> >        pointer that is a parameter to this function. */
> > !   n1 = PHI_ARG_DEF (def, 0);
> > !   n2 = PHI_ARG_DEF (def, 1);
> >     if (!ipa_is_ssa_with_stmt_def (n1) || !ipa_is_ssa_with_stmt_def (n2))
> >       return;
> > !   d1 = SSA_NAME_DEF_STMT (n1);
> > !   d2 = SSA_NAME_DEF_STMT (n2);
> >
> > !   join = gimple_bb (def);
> >     if ((rec = ipa_get_stmt_member_ptr_load_param (d1, false, &offset)))
> >       {
> >         if (ipa_get_stmt_member_ptr_load_param (d2, false, NULL))
> > --- 2031,2046 ----
> >
> >     /* First, we need to check whether one of these is a load from a member
> >        pointer that is a parameter to this function. */
> > !   tree n1 = PHI_ARG_DEF (def, 0);
> > !   tree n2 = PHI_ARG_DEF (def, 1);
> >     if (!ipa_is_ssa_with_stmt_def (n1) || !ipa_is_ssa_with_stmt_def (n2))
> >       return;
> > !   gimple d1 = SSA_NAME_DEF_STMT (n1);
> > !   gimple d2 = SSA_NAME_DEF_STMT (n2);
> >
> > !   tree rec;
> > !   basic_block bb, virt_bb;
> > !   basic_block join = gimple_bb (def);
> >     if ((rec = ipa_get_stmt_member_ptr_load_param (d1, false, &offset)))
> >       {
> >         if (ipa_get_stmt_member_ptr_load_param (d2, false, NULL))
> > *************** ipa_analyze_indirect_call_uses (struct c
> > *** 1939,1945 ****
> >     /* Third, let's see that the branching is done depending on the least
> >        significant bit of the pfn. */
> >
> > !   branch = last_stmt (bb);
> >     if (!branch || gimple_code (branch) != GIMPLE_COND)
> >       return;
> >
> > --- 2068,2074 ----
> >     /* Third, let's see that the branching is done depending on the least
> >        significant bit of the pfn. */
> >
> > !   gimple branch = last_stmt (bb);
> >     if (!branch || gimple_code (branch) != GIMPLE_COND)
> >       return;
> >
> > *************** ipa_analyze_indirect_call_uses (struct c
> > *** 1948,1954 ****
> >         || !integer_zerop (gimple_cond_rhs (branch)))
> >       return;
> >
> > !   cond = gimple_cond_lhs (branch);
> >     if (!ipa_is_ssa_with_stmt_def (cond))
> >       return;
> >
> > --- 2077,2083 ----
> >         || !integer_zerop (gimple_cond_rhs (branch)))
> >       return;
> >
> > !   tree cond = gimple_cond_lhs (branch);
> >     if (!ipa_is_ssa_with_stmt_def (cond))
> >       return;
> >
> > *************** ipa_analyze_indirect_call_uses (struct c
> > *** 1973,1978 ****
> > --- 2102,2108 ----
> >         def = SSA_NAME_DEF_STMT (cond);
> >       }
> >
> > +   tree rec2;
> >     rec2 = ipa_get_stmt_member_ptr_load_param (def,
> >                                              (TARGET_PTRMEMFUNC_VBIT_LOCATION
> >                                               == ptrmemfunc_vbit_in_delta),
> > *************** ipa_analyze_indirect_call_uses (struct c
> > *** 1982,1990 ****
> >
> >     index = ipa_get_param_decl_index (info, rec);
> >     if (index >= 0
> > !       && parm_preserved_before_stmt_p (&parms_ainfo[index], call, rec))
> >       {
> > !       struct cgraph_edge *cs = ipa_note_param_call (node, index, call);
> >         if (cs->indirect_info->offset != offset)
> >         cs->indirect_info->outer_type = NULL;
> >         cs->indirect_info->offset = offset;
> > --- 2112,2120 ----
> >
> >     index = ipa_get_param_decl_index (info, rec);
> >     if (index >= 0
> > !       && parm_preserved_before_stmt_p (fbi, index, call, rec))
> >       {
> > !       struct cgraph_edge *cs = ipa_note_param_call (fbi->node, index, call);
> >         if (cs->indirect_info->offset != offset)
> >         cs->indirect_info->outer_type = NULL;
> >         cs->indirect_info->offset = offset;
> > *************** ipa_analyze_indirect_call_uses (struct c
> > *** 1997,2012 ****
> >
> >   /* Analyze a CALL to an OBJ_TYPE_REF which is passed in TARGET and if the
> >      object referenced in the expression is a formal parameter of the caller
> > !    (described by INFO), create a call note for the statement. */
> >
> >   static void
> > ! ipa_analyze_virtual_call_uses (struct cgraph_node *node,
> > !                              struct ipa_node_params *info, gimple call,
> > !                              tree target)
> >   {
> > -   struct cgraph_edge *cs;
> > -   struct cgraph_indirect_call_info *ii;
> > -   struct ipa_jump_func jfunc;
> >     tree obj = OBJ_TYPE_REF_OBJECT (target);
> >     int index;
> >     HOST_WIDE_INT anc_offset;
> > --- 2127,2139 ----
> >
> >   /* Analyze a CALL to an OBJ_TYPE_REF which is passed in TARGET and if the
> >      object referenced in the expression is a formal parameter of the caller
> > !    FBI->node (described by FBI->info), create a call note for the
> > !    statement.  */
> >
> >   static void
> > ! ipa_analyze_virtual_call_uses (struct func_body_info *fbi,
> > !                              gimple call, tree target)
> >   {
> >     tree obj = OBJ_TYPE_REF_OBJECT (target);
> >     int index;
> >     HOST_WIDE_INT anc_offset;
> > *************** ipa_analyze_virtual_call_uses (struct cg
> > *** 2017,2024 ****
> > --- 2144,2153 ----
> >     if (TREE_CODE (obj) != SSA_NAME)
> >       return;
> >
> > +   struct ipa_node_params *info = fbi->info;
> >     if (SSA_NAME_IS_DEFAULT_DEF (obj))
> >       {
> > +       struct ipa_jump_func jfunc;
> >         if (TREE_CODE (SSA_NAME_VAR (obj)) != PARM_DECL)
> >         return;
> >
> > *************** ipa_analyze_virtual_call_uses (struct cg
> > *** 2031,2036 ****
> > --- 2160,2166 ----
> >       }
> >     else
> >       {
> > +       struct ipa_jump_func jfunc;
> >         gimple stmt = SSA_NAME_DEF_STMT (obj);
> >         tree expr;
> >
> > *************** ipa_analyze_virtual_call_uses (struct cg
> > *** 2045,2052 ****
> >         return;
> >       }
> >
> > !   cs = ipa_note_param_call (node, index, call);
> > !   ii = cs->indirect_info;
> >     ii->offset = anc_offset;
> >     ii->otr_token = tree_to_uhwi (OBJ_TYPE_REF_TOKEN (target));
> >     ii->otr_type = obj_type_ref_class (target);
> > --- 2175,2182 ----
> >         return;
> >       }
> >
> > !   struct cgraph_edge *cs = ipa_note_param_call (fbi->node, index, call);
> > !   struct cgraph_indirect_call_info *ii = cs->indirect_info;
> >     ii->offset = anc_offset;
> >     ii->otr_token = tree_to_uhwi (OBJ_TYPE_REF_TOKEN (target));
> >     ii->otr_type = obj_type_ref_class (target);
> > *************** ipa_analyze_virtual_call_uses (struct cg
> > *** 2058,2069 ****
> >      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_ainfo, gimple call)
> >   {
> >     tree target = gimple_call_fn (call);
> > -   struct cgraph_edge *cs;
> >
> >     if (!target
> >         || (TREE_CODE (target) != SSA_NAME
> > --- 2188,2196 ----
> >      containing intermediate information about each formal parameter.  */
> >
> >   static void
> > ! ipa_analyze_call_uses (struct func_body_info *fbi, gimple call)
> >   {
> >     tree target = gimple_call_fn (call);
> >
> >     if (!target
> >         || (TREE_CODE (target) != SSA_NAME
> > *************** ipa_analyze_call_uses (struct cgraph_nod
> > *** 2072,2098 ****
> >
> >     /* If we previously turned the call into a direct call, there is
> >        no need to analyze.  */
> > !   cs = cgraph_edge (node, call);
> >     if (cs && !cs->indirect_unknown_callee)
> >       return;
> >     if (TREE_CODE (target) == SSA_NAME)
> > !     ipa_analyze_indirect_call_uses (node, info, parms_ainfo, call, target);
> >     else if (virtual_method_call_p (target))
> > !     ipa_analyze_virtual_call_uses (node, info, call, target);
> >   }
> >
> >
> >   /* 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_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,
> > !                      struct param_analysis_info *parms_ainfo, gimple stmt)
> >   {
> >     if (is_gimple_call (stmt))
> > !     ipa_analyze_call_uses (node, info, parms_ainfo, stmt);
> >   }
> >
> >   /* Callback of walk_stmt_load_store_addr_ops for the visit_load.
> > --- 2199,2223 ----
> >
> >     /* If we previously turned the call into a direct call, there is
> >        no need to analyze.  */
> > !   struct cgraph_edge *cs = cgraph_edge (fbi->node, call);
> >     if (cs && !cs->indirect_unknown_callee)
> >       return;
> >     if (TREE_CODE (target) == SSA_NAME)
> > !     ipa_analyze_indirect_call_uses (fbi, call, target);
> >     else if (virtual_method_call_p (target))
> > !     ipa_analyze_virtual_call_uses (fbi, call, target);
> >   }
> >
> >
> >   /* Analyze the call statement STMT with respect to formal parameters (described
> > !    in INFO) of caller given by FBI->NODE.  Currently it only checks whether
> > !    formal parameters are called.  */
> >
> >   static void
> > ! ipa_analyze_stmt_uses (struct func_body_info *fbi, gimple stmt)
> >   {
> >     if (is_gimple_call (stmt))
> > !     ipa_analyze_call_uses (fbi, stmt);
> >   }
> >
> >   /* Callback of walk_stmt_load_store_addr_ops for the visit_load.
> > *************** visit_ref_for_mod_analysis (gimple, tree
> > *** 2116,2152 ****
> >     return false;
> >   }
> >
> > ! /* 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_AINFO is a pointer to a
> > !    vector containing intermediate information about each formal parameter.   */
> >
> >   static void
> > ! ipa_analyze_params_uses (struct cgraph_node *node,
> > !                        struct param_analysis_info *parms_ainfo)
> >   {
> > -   tree decl = node->decl;
> > -   basic_block bb;
> > -   struct function *func;
> >     gimple_stmt_iterator gsi;
> > !   struct ipa_node_params *info = IPA_NODE_REF (node);
> > !   int i;
> >
> > !   if (ipa_get_param_count (info) == 0 || info->uses_analysis_done)
> > !     return;
> >
> > !   info->uses_analysis_done = 1;
> > !   if (ipa_func_spec_opts_forbid_analysis_p (node))
> > !     {
> > !       for (i = 0; i < ipa_get_param_count (info); i++)
> > !       {
> > !         ipa_set_param_used (info, i, true);
> > !         ipa_set_controlled_uses (info, i, IPA_UNDESCRIBED_USE);
> > !       }
> > !       return;
> > !     }
> >
> > !   for (i = 0; i < ipa_get_param_count (info); i++)
> >       {
> >         tree parm = ipa_get_param (info, i);
> >         int controlled_uses = 0;
> > --- 2241,2283 ----
> >     return false;
> >   }
> >
> > ! /* Scan the statements in BB 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.  FBI holds various data about
> > !    the function being analyzed.  */
> >
> >   static void
> > ! ipa_analyze_params_uses_in_bb (struct func_body_info *fbi, basic_block bb)
> >   {
> >     gimple_stmt_iterator gsi;
> > !   for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
> > !     {
> > !       gimple stmt = gsi_stmt (gsi);
> >
> > !       if (is_gimple_debug (stmt))
> > !       continue;
> >
> > !       ipa_analyze_stmt_uses (fbi, stmt);
> > !       walk_stmt_load_store_addr_ops (stmt, fbi->info,
> > !                                    visit_ref_for_mod_analysis,
> > !                                    visit_ref_for_mod_analysis,
> > !                                    visit_ref_for_mod_analysis);
> > !     }
> > !   for (gsi = gsi_start_phis (bb); !gsi_end_p (gsi); gsi_next (&gsi))
> > !     walk_stmt_load_store_addr_ops (gsi_stmt (gsi), fbi->info,
> > !                                  visit_ref_for_mod_analysis,
> > !                                  visit_ref_for_mod_analysis,
> > !                                  visit_ref_for_mod_analysis);
> > ! }
> > !
> > ! /* Calculate controlled uses of parameters of NODE.  */
> > !
> > ! static void
> > ! ipa_analyze_controlled_uses (struct cgraph_node *node)
> > ! {
> > !   struct ipa_node_params *info = IPA_NODE_REF (node);
> >
> > !   for (int i = 0; i < ipa_get_param_count (info); i++)
> >       {
> >         tree parm = ipa_get_param (info, i);
> >         int controlled_uses = 0;
> > *************** ipa_analyze_params_uses (struct cgraph_n
> > *** 2182,2226 ****
> >         controlled_uses = IPA_UNDESCRIBED_USE;
> >         ipa_set_controlled_uses (info, i, controlled_uses);
> >       }
> >
> > !   func = DECL_STRUCT_FUNCTION (decl);
> > !   FOR_EACH_BB_FN (bb, func)
> > !     {
> > !       for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
> > !       {
> > !         gimple stmt = gsi_stmt (gsi);
> > !
> > !         if (is_gimple_debug (stmt))
> > !           continue;
> >
> > !         ipa_analyze_stmt_uses (node, info, parms_ainfo, stmt);
> > !         walk_stmt_load_store_addr_ops (stmt, info,
> > !                                        visit_ref_for_mod_analysis,
> > !                                        visit_ref_for_mod_analysis,
> > !                                        visit_ref_for_mod_analysis);
> > !       }
> > !       for (gsi = gsi_start_phis (bb); !gsi_end_p (gsi); gsi_next (&gsi))
> > !       walk_stmt_load_store_addr_ops (gsi_stmt (gsi), info,
> > !                                      visit_ref_for_mod_analysis,
> > !                                      visit_ref_for_mod_analysis,
> > !                                      visit_ref_for_mod_analysis);
> > !     }
> >   }
> >
> > ! /* Free stuff in PARMS_AINFO, assume there are PARAM_COUNT parameters.  */
> >
> > ! static void
> > ! free_parms_ainfo (struct param_analysis_info *parms_ainfo, int param_count)
> >   {
> > !   int i;
> >
> > !   for (i = 0; i < param_count; i++)
> > !     {
> > !       if (parms_ainfo[i].parm_visited_statements)
> > !       BITMAP_FREE (parms_ainfo[i].parm_visited_statements);
> > !       if (parms_ainfo[i].pt_visited_statements)
> > !       BITMAP_FREE (parms_ainfo[i].pt_visited_statements);
> > !     }
> >   }
> >
> >   /* Initialize the array describing properties of of formal parameters
> > --- 2313,2348 ----
> >         controlled_uses = IPA_UNDESCRIBED_USE;
> >         ipa_set_controlled_uses (info, i, controlled_uses);
> >       }
> > + }
> >
> > ! /* Free stuff in BI.  */
> >
> > ! static void
> > ! free_ipa_bb_info (struct ipa_bb_info *bi)
> > ! {
> > !   bi->cg_edges.release ();
> > !   bi->paas.release ();
> >   }
> >
> > ! /* Dominator walker driving the analysis.  */
> >
> > ! class analysis_dom_walker : public dom_walker
> >   {
> > ! public:
> > !   analysis_dom_walker (struct func_body_info *fbi)
> > !     : dom_walker (CDI_DOMINATORS), m_fbi (fbi) {}
> >
> > !   virtual void before_dom_children (basic_block);
> > !
> > ! private:
> > !   struct func_body_info *m_fbi;
> > ! };
> > !
> > ! void
> > ! analysis_dom_walker::before_dom_children (basic_block bb)
> > ! {
> > !   ipa_analyze_params_uses_in_bb (m_fbi, bb);
> > !   ipa_compute_jump_functions_for_bb (m_fbi, bb);
> >   }
> >
> >   /* Initialize the array describing properties of of formal parameters
> > *************** free_parms_ainfo (struct param_analysis_
> > *** 2230,2253 ****
> >   void
> >   ipa_analyze_node (struct cgraph_node *node)
> >   {
> >     struct ipa_node_params *info;
> > -   struct param_analysis_info *parms_ainfo;
> > -   int param_count;
> >
> >     ipa_check_create_node_params ();
> >     ipa_check_create_edge_args ();
> >     info = IPA_NODE_REF (node);
> > !   push_cfun (DECL_STRUCT_FUNCTION (node->decl));
> >     ipa_initialize_node_params (node);
> >
> > !   param_count = ipa_get_param_count (info);
> > !   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_ainfo);
> > !   ipa_compute_jump_functions (node, parms_ainfo);
> >
> > !   free_parms_ainfo (parms_ainfo, param_count);
> >     pop_cfun ();
> >   }
> >
> > --- 2352,2411 ----
> >   void
> >   ipa_analyze_node (struct cgraph_node *node)
> >   {
> > +   struct func_body_info fbi;
> >     struct ipa_node_params *info;
> >
> >     ipa_check_create_node_params ();
> >     ipa_check_create_edge_args ();
> >     info = IPA_NODE_REF (node);
> > !
> > !   if (info->analysis_done)
> > !     return;
> > !   info->analysis_done = 1;
> > !
> > !   if (ipa_func_spec_opts_forbid_analysis_p (node))
> > !     {
> > !       for (int i = 0; i < ipa_get_param_count (info); i++)
> > !       {
> > !         ipa_set_param_used (info, i, true);
> > !         ipa_set_controlled_uses (info, i, IPA_UNDESCRIBED_USE);
> > !       }
> > !       return;
> > !     }
> > !
> > !   struct function *func = DECL_STRUCT_FUNCTION (node->decl);
> > !   push_cfun (func);
> > !   calculate_dominance_info (CDI_DOMINATORS);
> >     ipa_initialize_node_params (node);
> > +   ipa_analyze_controlled_uses (node);
> >
> > !   fbi.node = node;
> > !   fbi.info = IPA_NODE_REF (node);
> > !   fbi.ibbis = vNULL;
> > !   fbi.ibbis.safe_grow_cleared (last_basic_block_for_fn (cfun));
> > !   fbi.param_count = ipa_get_param_count (info);
> > !   fbi.aa_walked = 0;
> >
> > !   for (struct cgraph_edge *cs = node->callees; cs; cs = cs->next_callee)
> > !     {
> > !       ipa_bb_info *bi = ipa_get_bb_info (&fbi, gimple_bb (cs->call_stmt));
> > !       bi->cg_edges.safe_push (cs);
> > !     }
> >
> > !   for (struct cgraph_edge *cs = node->indirect_calls; cs; cs = cs->next_callee)
> > !     {
> > !       ipa_bb_info *bi = ipa_get_bb_info (&fbi, gimple_bb (cs->call_stmt));
> > !       bi->cg_edges.safe_push (cs);
> > !     }
> > !
> > !   analysis_dom_walker (&fbi).walk (ENTRY_BLOCK_PTR_FOR_FN (cfun));
> > !
> > !   int i;
> > !   struct ipa_bb_info *bi;
> > !   FOR_EACH_VEC_ELT (fbi.ibbis, i, bi)
> > !     free_ipa_bb_info (bi);
> > !   fbi.ibbis.release ();
> > !   free_dominance_info (CDI_DOMINATORS);
> >     pop_cfun ();
> >   }
> >
> > *************** ipa_node_duplication_hook (struct cgraph
> > *** 3299,3305 ****
> >     new_info->lattices = NULL;
> >     new_info->ipcp_orig_node = old_info->ipcp_orig_node;
> >
> > !   new_info->uses_analysis_done = old_info->uses_analysis_done;
> >     new_info->node_enqueued = old_info->node_enqueued;
> >
> >     old_av = ipa_get_agg_replacements_for_node (src);
> > --- 3457,3463 ----
> >     new_info->lattices = NULL;
> >     new_info->ipcp_orig_node = old_info->ipcp_orig_node;
> >
> > !   new_info->analysis_done = old_info->analysis_done;
> >     new_info->node_enqueued = old_info->node_enqueued;
> >
> >     old_av = ipa_get_agg_replacements_for_node (src);
> > *************** ipa_write_node_info (struct output_block
> > *** 4424,4430 ****
> >     for (j = 0; j < ipa_get_param_count (info); j++)
> >       streamer_write_uhwi (ob, ipa_get_param_move_cost (info, j));
> >     bp = bitpack_create (ob->main_stream);
> > !   gcc_assert (info->uses_analysis_done
> >               || ipa_get_param_count (info) == 0);
> >     gcc_assert (!info->node_enqueued);
> >     gcc_assert (!info->ipcp_orig_node);
> > --- 4582,4588 ----
> >     for (j = 0; j < ipa_get_param_count (info); j++)
> >       streamer_write_uhwi (ob, ipa_get_param_move_cost (info, j));
> >     bp = bitpack_create (ob->main_stream);
> > !   gcc_assert (info->analysis_done
> >               || ipa_get_param_count (info) == 0);
> >     gcc_assert (!info->node_enqueued);
> >     gcc_assert (!info->ipcp_orig_node);
> > *************** ipa_read_node_info (struct lto_input_blo
> > *** 4470,4476 ****
> >
> >     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++)
> >       ipa_set_param_used (info, k, bp_unpack_value (&bp, 1));
> > --- 4628,4634 ----
> >
> >     bp = streamer_read_bitpack (ib);
> >     if (ipa_get_param_count (info) != 0)
> > !     info->analysis_done = true;
> >     info->node_enqueued = false;
> >     for (k = 0; k < ipa_get_param_count (info); k++)
> >       ipa_set_param_used (info, k, bp_unpack_value (&bp, 1));
> > *************** adjust_agg_replacement_values (struct cg
> > *** 4820,4836 ****
> >       v->index = adj[v->index];
> >   }
> >
> >
> > ! /* Function body transformation phase.  */
> >
> >   unsigned int
> >   ipcp_transform_function (struct cgraph_node *node)
> >   {
> >     vec<ipa_param_descriptor> descriptors = vNULL;
> > !   struct param_analysis_info *parms_ainfo;
> >     struct ipa_agg_replacement_value *aggval;
> > -   gimple_stmt_iterator gsi;
> > -   basic_block bb;
> >     int param_count;
> >     bool cfg_changed = false, something_changed = false;
> >
> > --- 4978,5106 ----
> >       v->index = adj[v->index];
> >   }
> >
> > + /* Dominator walker driving the ipcp modification phase.  */
> > +
> > + class ipcp_modif_dom_walker : public dom_walker
> > + {
> > + public:
> > +   ipcp_modif_dom_walker (struct func_body_info *fbi,
> > +                        vec<ipa_param_descriptor> descs,
> > +                        struct ipa_agg_replacement_value *av,
> > +                        bool *sc, bool *cc)
> > +     : dom_walker (CDI_DOMINATORS), m_fbi (fbi), m_descriptors (descs),
> > +       m_aggval (av), m_something_changed (sc), m_cfg_changed (cc) {}
> > +
> > +   virtual void before_dom_children (basic_block);
> > +
> > + private:
> > +   struct func_body_info *m_fbi;
> > +   vec<ipa_param_descriptor> m_descriptors;
> > +   struct ipa_agg_replacement_value *m_aggval;
> > +   bool *m_something_changed, *m_cfg_changed;
> > + };
> > +
> > + void
> > + ipcp_modif_dom_walker::before_dom_children (basic_block bb)
> > + {
> > +   gimple_stmt_iterator gsi;
> > +   for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
> > +     {
> > +       struct ipa_agg_replacement_value *v;
> > +       gimple stmt = gsi_stmt (gsi);
> > +       tree rhs, val, t;
> > +       HOST_WIDE_INT offset, size;
> > +       int index;
> > +       bool by_ref, vce;
> > +
> > +       if (!gimple_assign_load_p (stmt))
> > +       continue;
> > +       rhs = gimple_assign_rhs1 (stmt);
> > +       if (!is_gimple_reg_type (TREE_TYPE (rhs)))
> > +       continue;
> >
> > !       vce = false;
> > !       t = rhs;
> > !       while (handled_component_p (t))
> > !       {
> > !         /* V_C_E can do things like convert an array of integers to one
> > !            bigger integer and similar things we do not handle below.  */
> > !         if (TREE_CODE (rhs) == VIEW_CONVERT_EXPR)
> > !           {
> > !             vce = true;
> > !             break;
> > !           }
> > !         t = TREE_OPERAND (t, 0);
> > !       }
> > !       if (vce)
> > !       continue;
> > !
> > !       if (!ipa_load_from_parm_agg_1 (m_fbi, m_descriptors, stmt, rhs, &index,
> > !                                    &offset, &size, &by_ref))
> > !       continue;
> > !       for (v = m_aggval; v; v = v->next)
> > !       if (v->index == index
> > !           && v->offset == offset)
> > !         break;
> > !       if (!v
> > !         || v->by_ref != by_ref
> > !         || tree_to_shwi (TYPE_SIZE (TREE_TYPE (v->value))) != size)
> > !       continue;
> > !
> > !       gcc_checking_assert (is_gimple_ip_invariant (v->value));
> > !       if (!useless_type_conversion_p (TREE_TYPE (rhs), TREE_TYPE (v->value)))
> > !       {
> > !         if (fold_convertible_p (TREE_TYPE (rhs), v->value))
> > !           val = fold_build1 (NOP_EXPR, TREE_TYPE (rhs), v->value);
> > !         else if (TYPE_SIZE (TREE_TYPE (rhs))
> > !                  == TYPE_SIZE (TREE_TYPE (v->value)))
> > !           val = fold_build1 (VIEW_CONVERT_EXPR, TREE_TYPE (rhs), v->value);
> > !         else
> > !           {
> > !             if (dump_file)
> > !               {
> > !                 fprintf (dump_file, "    const ");
> > !                 print_generic_expr (dump_file, v->value, 0);
> > !                 fprintf (dump_file, "  can't be converted to type of ");
> > !                 print_generic_expr (dump_file, rhs, 0);
> > !                 fprintf (dump_file, "\n");
> > !               }
> > !             continue;
> > !           }
> > !       }
> > !       else
> > !       val = v->value;
> > !
> > !       if (dump_file && (dump_flags & TDF_DETAILS))
> > !       {
> > !         fprintf (dump_file, "Modifying stmt:\n  ");
> > !         print_gimple_stmt (dump_file, stmt, 0, 0);
> > !       }
> > !       gimple_assign_set_rhs_from_tree (&gsi, val);
> > !       update_stmt (stmt);
> > !
> > !       if (dump_file && (dump_flags & TDF_DETAILS))
> > !       {
> > !         fprintf (dump_file, "into:\n  ");
> > !         print_gimple_stmt (dump_file, stmt, 0, 0);
> > !         fprintf (dump_file, "\n");
> > !       }
> > !
> > !       *m_something_changed = true;
> > !       if (maybe_clean_eh_stmt (stmt)
> > !         && gimple_purge_dead_eh_edges (gimple_bb (stmt)))
> > !       *m_cfg_changed = true;
> > !     }
> > !
> > ! }
> > !
> > ! /* IPCP transformation phase doing propagation of aggregate values.  */
> >
> >   unsigned int
> >   ipcp_transform_function (struct cgraph_node *node)
> >   {
> >     vec<ipa_param_descriptor> descriptors = vNULL;
> > !   struct func_body_info fbi;
> >     struct ipa_agg_replacement_value *aggval;
> >     int param_count;
> >     bool cfg_changed = false, something_changed = false;
> >
> > *************** ipcp_transform_function (struct cgraph_n
> > *** 4850,4951 ****
> >     adjust_agg_replacement_values (node, aggval);
> >     if (dump_file)
> >       ipa_dump_agg_replacement_values (dump_file, aggval);
> > -   parms_ainfo = XALLOCAVEC (struct param_analysis_info, param_count);
> > -   memset (parms_ainfo, 0, sizeof (struct param_analysis_info) * param_count);
> > -   descriptors.safe_grow_cleared (param_count);
> > -   ipa_populate_param_decls (node, descriptors);
> > -
> > -   FOR_EACH_BB_FN (bb, cfun)
> > -     for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
> > -       {
> > -       struct ipa_agg_replacement_value *v;
> > -       gimple stmt = gsi_stmt (gsi);
> > -       tree rhs, val, t;
> > -       HOST_WIDE_INT offset, size;
> > -       int index;
> > -       bool by_ref, vce;
> > -
> > -       if (!gimple_assign_load_p (stmt))
> > -         continue;
> > -       rhs = gimple_assign_rhs1 (stmt);
> > -       if (!is_gimple_reg_type (TREE_TYPE (rhs)))
> > -         continue;
> > -
> > -       vce = false;
> > -       t = rhs;
> > -       while (handled_component_p (t))
> > -         {
> > -           /* V_C_E can do things like convert an array of integers to one
> > -                bigger integer and similar things we do not handle below.  */
> > -             if (TREE_CODE (rhs) == VIEW_CONVERT_EXPR)
> > -             {
> > -               vce = true;
> > -               break;
> > -             }
> > -           t = TREE_OPERAND (t, 0);
> > -         }
> > -       if (vce)
> > -         continue;
> >
> > !       if (!ipa_load_from_parm_agg_1 (descriptors, parms_ainfo, stmt,
> > !                                      rhs, &index, &offset, &size, &by_ref))
> > !         continue;
> > !       for (v = aggval; v; v = v->next)
> > !         if (v->index == index
> > !             && v->offset == offset)
> > !           break;
> > !       if (!v
> > !           || v->by_ref != by_ref
> > !           || tree_to_shwi (TYPE_SIZE (TREE_TYPE (v->value))) != size)
> > !         continue;
> >
> > !       gcc_checking_assert (is_gimple_ip_invariant (v->value));
> > !       if (!useless_type_conversion_p (TREE_TYPE (rhs), TREE_TYPE (v->value)))
> > !         {
> > !           if (fold_convertible_p (TREE_TYPE (rhs), v->value))
> > !             val = fold_build1 (NOP_EXPR, TREE_TYPE (rhs), v->value);
> > !           else if (TYPE_SIZE (TREE_TYPE (rhs))
> > !                    == TYPE_SIZE (TREE_TYPE (v->value)))
> > !             val = fold_build1 (VIEW_CONVERT_EXPR, TREE_TYPE (rhs), v->value);
> > !           else
> > !             {
> > !               if (dump_file)
> > !                 {
> > !                   fprintf (dump_file, "    const ");
> > !                   print_generic_expr (dump_file, v->value, 0);
> > !                   fprintf (dump_file, "  can't be converted to type of ");
> > !                   print_generic_expr (dump_file, rhs, 0);
> > !                   fprintf (dump_file, "\n");
> > !                 }
> > !               continue;
> > !             }
> > !         }
> > !       else
> > !         val = v->value;
> > !
> > !       if (dump_file && (dump_flags & TDF_DETAILS))
> > !         {
> > !           fprintf (dump_file, "Modifying stmt:\n  ");
> > !           print_gimple_stmt (dump_file, stmt, 0, 0);
> > !         }
> > !       gimple_assign_set_rhs_from_tree (&gsi, val);
> > !       update_stmt (stmt);
> > !
> > !       if (dump_file && (dump_flags & TDF_DETAILS))
> > !         {
> > !           fprintf (dump_file, "into:\n  ");
> > !           print_gimple_stmt (dump_file, stmt, 0, 0);
> > !           fprintf (dump_file, "\n");
> > !         }
> > !
> > !       something_changed = true;
> > !       if (maybe_clean_eh_stmt (stmt)
> > !           && gimple_purge_dead_eh_edges (gimple_bb (stmt)))
> > !         cfg_changed = true;
> > !       }
> >
> >     (*ipa_node_agg_replacements)[node->uid] = NULL;
> > -   free_parms_ainfo (parms_ainfo, param_count);
> >     descriptors.release ();
> >
> >     if (!something_changed)
> > --- 5120,5146 ----
> >     adjust_agg_replacement_values (node, aggval);
> >     if (dump_file)
> >       ipa_dump_agg_replacement_values (dump_file, aggval);
> >
> > !   fbi.node = node;
> > !   fbi.info = NULL;
> > !   fbi.ibbis = vNULL;
> > !   fbi.ibbis.safe_grow_cleared (last_basic_block_for_fn (cfun));
> > !   fbi.param_count = param_count;
> > !   fbi.aa_walked = 0;
> >
> > !   descriptors.safe_grow_cleared (param_count);
> > !   ipa_populate_param_decls (node, descriptors);
> > !   calculate_dominance_info (CDI_DOMINATORS);
> > !   ipcp_modif_dom_walker (&fbi, descriptors, aggval, &something_changed,
> > !                        &cfg_changed).walk (ENTRY_BLOCK_PTR_FOR_FN (cfun));
> >
> > +   int i;
> > +   struct ipa_bb_info *bi;
> > +   FOR_EACH_VEC_ELT (fbi.ibbis, i, bi)
> > +     free_ipa_bb_info (bi);
> > +   fbi.ibbis.release ();
> > +   free_dominance_info (CDI_DOMINATORS);
> >     (*ipa_node_agg_replacements)[node->uid] = NULL;
> >     descriptors.release ();
> >
> >     if (!something_changed)
> > Index: src/gcc/ipa-prop.h
> > ===================================================================
> > *** src.orig/gcc/ipa-prop.h
> > --- src/gcc/ipa-prop.h
> > *************** struct ipa_node_params
> > *** 371,378 ****
> >     /* If this node is an ipa-cp clone, these are the known values that describe
> >        what it has been specialized for.  */
> >     vec<tree> known_vals;
> > !   /* Whether the param uses analysis has already been performed.  */
> > !   unsigned uses_analysis_done : 1;
> >     /* Whether the function is enqueued in ipa-cp propagation stack.  */
> >     unsigned node_enqueued : 1;
> >     /* Whether we should create a specialized version based on values that are
> > --- 371,379 ----
> >     /* If this node is an ipa-cp clone, these are the known values that describe
> >        what it has been specialized for.  */
> >     vec<tree> known_vals;
> > !   /* Whether the param uses analysis and jump function computation has already
> > !      been performed.  */
> > !   unsigned analysis_done : 1;
> >     /* Whether the function is enqueued in ipa-cp propagation stack.  */
> >     unsigned node_enqueued : 1;
> >     /* Whether we should create a specialized version based on values that are
> > Index: src/gcc/params.def
> > ===================================================================
> > *** src.orig/gcc/params.def
> > --- src/gcc/params.def
> > *************** DEFPARAM (PARAM_IPA_MAX_AGG_ITEMS,
> > *** 947,952 ****
> > --- 947,958 ----
> >           "jump functions and lattices",
> >           16, 0, 0)
> >
> > + DEFPARAM (PARAM_IPA_MAX_AA_STEPS,
> > +         "ipa-max-aa-steps",
> > +         "Maximum number of statements that will be visited by IPA formal "
> > +         "parameter analysis based on alias analysis in any given function",
> > +         100000, 0, 0)
> > +
> >   DEFPARAM (PARAM_IPA_CP_LOOP_HINT_BONUS,
> >           "ipa-cp-loop-hint-bonus",
> >           "Compile-time bonus IPA-CP assigns to candidates which make loop "
> >

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH] Make ipa-prop analyze BBs in DOM order
  2014-04-28 10:06   ` Martin Jambor
@ 2014-04-28 11:44     ` Richard Biener
  0 siblings, 0 replies; 5+ messages in thread
From: Richard Biener @ 2014-04-28 11:44 UTC (permalink / raw)
  To: Richard Biener, GCC Patches, Jan Hubicka

On Mon, Apr 28, 2014 at 12:03 PM, Martin Jambor <mjambor@suse.cz> wrote:
> Hi,
>
> On Mon, Apr 28, 2014 at 11:01:45AM +0200, Richard Biener wrote:
>> On Fri, Apr 25, 2014 at 5:12 PM, Martin Jambor <mjambor@suse.cz> wrote:
>> > Hi,
>> >
>> > the following patch deals with requested propagation in PR 53787 in
>> > the real benchmark (as opposed to the original simple testcase) by
>> > analyzing individual BBs in ipa-prop.c in dominator order.
>> >
>> > Currently we do the analysis in two loops, in the first the order is
>> > given by FOR_EACH_BB_FN and in the second the order is the order of
>> > call graph edges (which in practice is quite bad because we tend to
>> > start with BBs towards the end).  When analysis determines that a
>> > non-SSA parameter or that data pointed to by a parameter are modified,
>> > this is marked into a function wide flag (describing the parameter)
>> > and we always consider the data clobbered from that moment on in order
>> > to save AA walking.
>> >
>> > This patch changes the analysis into dominator order and data is
>> > considered clobbered only in dominator children of a block where it
>> > was determined to be possibly clobbered, not in the whole function.
>> > This was confirmed to help in the aforementioned PR.
>> >
>> > The patch also, enforces a cap on the number of statements walked
>> > (approx. 4 times the highest I have ever seen).  On the other hand it
>> > gives up trying to cache the bitmap of visited memory-SSAs.  The
>> > per-BB information had to be put somewhere and I took this opportunity
>> > to cram a lot of commonly used per-function data into the same
>> > structure, which is then passed among various functions.  The new
>> > structure replaces the struct param_analysis_info.
>> >
>> > Bootstrapped and tested on x86_64-linux, I have also LTO-built Firefox
>> > at -O3 with it.  OK for trunk?
>>
>> 100000 is a very big number - is that a count for the whole program?
>
> The limit is per function.  I thought I lost my measurements but today
> I have found them.  Apparently the highest number of visited
> definitions I have measured was 13689 in algnci.fppized.f (from
> something in SpecFP 2006) and that was a big outlier (e.g. the biggest
> number during bootstrap was 3798 in insn-attrtab.c).  I'm sorry I
> misremembered the record, I really thought it was over 20 thousand.
> I'll lower the limit to 50000 then.  Or even 25000 if that is
> considered too big but the limit is really intended to guard against
> pathological cases.

Well.  DCE limits it to 128*128.  I'd say on the order of 10000 is ok,
so 25000 would be fine with me.

>> Did you make sure to excercise the fallback path by for example
>> bootstrapping or building firefox with a much lower number (say, 1)?
>
> I didn't but...
>
>>
>> Walking all immediate dominators as fallback possibly visits
>> on the order of O (n_basic_blocks) blocks, so it isn't really "fast".
>> It's surely faster than doing the oracle walk, but can't we have a
>> quicker fallback (like fail?)
>
> ...the fallback is to fail (see all calls to aa_overwalked).
> I.e. when the limit is reached, from that moment on, all memory is
> considered clobbered and no AA is performed on that function as a part
> of ipa_analyze_node or IPA-CP transformation phase.  It is the
> analysis itself that is done in DOM order (as opposed to the order of
> call graph edges) and once AA fails in a BB, we remember not to bother
> with that parameter in all DOM children, regardless of the cap.

Ah, ok.  You still might want to try a bootstrap with the limit set to 1.

> Still potentially problematic are callers in ipa-inline-analysis.c but
> they have always been, we have never had any guards there.  Making
> them adhere to these limits means that IPA-CP and ipa-inline need to
> share struct func_body_info during the analysis stage so it requires
> some coordination with Honza.  This will also increase the chance of
> hitting the limit, of course :-)

Yeah, well ...

Richard.

> Martin
>
>>
>> Thanks,
>> Richard.
>>
>> > Thanks,
>> >
>> > Martin
>> >
>> >
>> > 2014-02-12  Martin Jambor  <mjambor@suse.cz>
>> >
>> >         PR tree-optimization/53787
>> >         * params.def (PARAM_IPA_CP_LOOP_HINT_BONUS): New param.
>> >         * ipa-prop.h (ipa_node_params): Rename uses_analysis_done to
>> >         analysis_done, update all uses.
>> >         * ipa-prop.c: Include domwalk.h
>> >         (param_analysis_info): Removed.
>> >         (param_aa_status): New type.
>> >         (ipa_bb_info): Likewise.
>> >         (func_body_info): Likewise.
>> >         (ipa_get_bb_info): New function.
>> >         (aa_overwalked): Likewise.
>> >         (find_dominating_aa_status): Likewise.
>> >         (parm_bb_aa_status_for_bb): Likewise.
>> >         (parm_preserved_before_stmt_p): Changed to use new param AA info.
>> >         (load_from_unmodified_param): Accept func_body_info as a parameter
>> >         instead of parms_ainfo.
>> >         (parm_ref_data_preserved_p): Changed to use new param AA info.
>> >         (parm_ref_data_pass_through_p): Likewise.
>> >         (ipa_load_from_parm_agg_1): Likewise.  Update callers.
>> >         (compute_complex_assign_jump_func): Changed to use new param AA info.
>> >         (compute_complex_ancestor_jump_func): Likewise.
>> >         (ipa_compute_jump_functions_for_edge): Likewise.
>> >         (ipa_compute_jump_functions): Removed.
>> >         (ipa_compute_jump_functions_for_bb): New function.
>> >         (ipa_analyze_indirect_call_uses): Likewise, moved variable
>> >         declarations down.
>> >         (ipa_analyze_virtual_call_uses): Accept func_body_info instead of node
>> >         and info, moved variable declarations down.
>> >         (ipa_analyze_call_uses): Accept and pass on func_body_info instead of
>> >         node and info.
>> >         (ipa_analyze_stmt_uses): Likewise.
>> >         (ipa_analyze_params_uses): Removed.
>> >         (ipa_analyze_params_uses_in_bb): New function.
>> >         (ipa_analyze_controlled_uses): Likewise.
>> >         (free_ipa_bb_info): Likewise.
>> >         (analysis_dom_walker): New class.
>> >         (ipa_analyze_node): Handle node-specific forbidden analysis,
>> >         initialize and free func_body_info, use dominator walker.
>> >         (ipcp_modif_dom_walker): New class.
>> >         (ipcp_transform_function): Create and free func_body_info, use
>> >         ipcp_modif_dom_walker, moved a lot of functionality there.
>> >
>> > Index: src/gcc/ipa-prop.c
>> > ===================================================================
>> > *** src.orig/gcc/ipa-prop.c
>> > --- src/gcc/ipa-prop.c
>> > *************** along with GCC; see the file COPYING3.
>> > *** 59,72 ****
>> >   #include "ipa-utils.h"
>> >   #include "stringpool.h"
>> >   #include "tree-ssanames.h"
>> >
>> > ! /* Intermediate information about a parameter that is only useful during the
>> > !    run of ipa_analyze_node and is not kept afterwards.  */
>> >
>> > ! struct param_analysis_info
>> >   {
>> >     bool parm_modified, ref_modified, pt_modified;
>> > !   bitmap parm_visited_statements, pt_visited_statements;
>> >   };
>> >
>> >   /* Vector where the parameter infos are actually stored. */
>> > --- 59,111 ----
>> >   #include "ipa-utils.h"
>> >   #include "stringpool.h"
>> >   #include "tree-ssanames.h"
>> > + #include "domwalk.h"
>> >
>> > ! /* Intermediate information that we get from AA analysis about a parameter.  */
>> >
>> > ! struct param_aa_status
>> >   {
>> > +   /* If not true, look at the dominator parent instead.  */
>> > +   bool valid;
>> > +
>> > +   /* Whether we have seen something which might have modified the data in
>> > +      question.  Parm is for the parameter itself, ref is for data it points to
>> > +      but using the alias type of individual accesses and pt is the same thing
>> > +      but for computing aggregate pass-through functions using a very inclusive
>> > +      ao_ref.  */
>> >     bool parm_modified, ref_modified, pt_modified;
>> > ! };
>> > !
>> > ! /* Information related to a given BB that used only when looking at function
>> > !    body.  */
>> > !
>> > ! struct ipa_bb_info
>> > ! {
>> > !   /* Call graph edges going out of this BB.  */
>> > !   vec<cgraph_edge_p> cg_edges;
>> > !   /* Alias analysis statuses of each formal parameter at this bb.  */
>> > !   vec<param_aa_status> paas;
>> > ! };
>> > !
>> > ! /* Structure with global information that is only used when looking at function
>> > !    body. */
>> > !
>> > ! struct func_body_info
>> > ! {
>> > !   /* The node that is being analyzed.  */
>> > !   cgraph_node *node;
>> > !
>> > !   /* Its info.  */
>> > !   struct ipa_node_params *info;
>> > !
>> > !   /* Information about individual BBs. */
>> > !   vec<ipa_bb_info> ibbis;
>> > !
>> > !   /* Number of parameters.  */
>> > !   int param_count;
>> > !
>> > !   /* Number of statements already walked by when analyzing this function.  */
>> > !   unsigned int aa_walked;
>> >   };
>> >
>> >   /* Vector where the parameter infos are actually stored. */
>> > *************** ipa_binfo_from_known_type_jfunc (struct
>> > *** 510,515 ****
>> > --- 549,564 ----
>> >                               jfunc->value.known_type.component_type);
>> >   }
>> >
>> > + /* Get IPA BB information about the given BB.  FBI is the context of analyzis
>> > +    of this function body.  */
>> > +
>> > + static struct ipa_bb_info *
>> > + ipa_get_bb_info (struct func_body_info *fbi, basic_block bb)
>> > + {
>> > +   gcc_checking_assert (fbi);
>> > +   return &fbi->ibbis[bb->index];
>> > + }
>> > +
>> >   /* Structure to be passed in between detect_type_change and
>> >      check_stmt_for_type_change.  */
>> >
>> > *************** mark_modified (ao_ref *ao ATTRIBUTE_UNUS
>> > *** 769,802 ****
>> >     return true;
>> >   }
>> >
>> >   /* Return true if a load from a formal parameter PARM_LOAD is known to retrieve
>> >      a value known not to be modified in this function before reaching the
>> > !    statement STMT.  PARM_AINFO is a pointer to a structure containing temporary
>> > !    information about the parameter.  */
>> >
>> >   static bool
>> > ! parm_preserved_before_stmt_p (struct param_analysis_info *parm_ainfo,
>> > !                              gimple stmt, tree parm_load)
>> >   {
>> >     bool modified = false;
>> > -   bitmap *visited_stmts;
>> >     ao_ref refd;
>> >
>> > !   if (parm_ainfo && parm_ainfo->parm_modified)
>> > !     return false;
>> >
>> >     gcc_checking_assert (gimple_vuse (stmt) != NULL_TREE);
>> >     ao_ref_init (&refd, parm_load);
>> > !   /* We can cache visited statements only when parm_ainfo is available and when
>> > !      we are looking at a naked load of the whole parameter.  */
>> > !   if (!parm_ainfo || TREE_CODE (parm_load) != PARM_DECL)
>> > !     visited_stmts = NULL;
>> > !   else
>> > !     visited_stmts = &parm_ainfo->parm_visited_statements;
>> > !   walk_aliased_vdefs (&refd, gimple_vuse (stmt), mark_modified, &modified,
>> > !                     visited_stmts);
>> > !   if (parm_ainfo && modified)
>> > !     parm_ainfo->parm_modified = true;
>> >     return !modified;
>> >   }
>> >
>> > --- 818,918 ----
>> >     return true;
>> >   }
>> >
>> > + /* Return true if we have already walked so many statements in AA that we
>> > +    should really just start giving up.  */
>> > +
>> > + static bool
>> > + aa_overwalked (struct func_body_info *fbi)
>> > + {
>> > +   gcc_checking_assert (fbi);
>> > +   return fbi->aa_walked > (unsigned) PARAM_VALUE (PARAM_IPA_MAX_AA_STEPS);
>> > + }
>> > +
>> > + /* Find the nearest valid aa status for parameter specified by INDEX that
>> > +    dominates BB.  */
>> > +
>> > + static struct param_aa_status *
>> > + find_dominating_aa_status (struct func_body_info *fbi, basic_block bb,
>> > +                          int index)
>> > + {
>> > +   while (true)
>> > +     {
>> > +       bb = get_immediate_dominator (CDI_DOMINATORS, bb);
>> > +       if (!bb)
>> > +       return NULL;
>> > +       struct ipa_bb_info *bi = ipa_get_bb_info (fbi, bb);
>> > +       if (!bi->paas.is_empty ()
>> > +         && bi->paas[index].valid)
>> > +       return &bi->paas[index];
>> > +     }
>> > + }
>> > +
>> > + /* Get AA status structure for the given BB and parameter with INDEX.  Allocate
>> > +    structures and/or intialize the result with a dominating description as
>> > +    necessary.  */
>> > +
>> > + static struct param_aa_status *
>> > + parm_bb_aa_status_for_bb (struct func_body_info *fbi, basic_block bb,
>> > +                         int index)
>> > + {
>> > +   gcc_checking_assert (fbi);
>> > +   struct ipa_bb_info *bi = ipa_get_bb_info (fbi, bb);
>> > +   if (bi->paas.is_empty ())
>> > +     bi->paas.safe_grow_cleared (fbi->param_count);
>> > +   struct param_aa_status *paa = &bi->paas[index];
>> > +   if (!paa->valid)
>> > +     {
>> > +       gcc_checking_assert (!paa->parm_modified
>> > +                          && !paa->ref_modified
>> > +                          && !paa->pt_modified);
>> > +       struct param_aa_status *dom_paa;
>> > +       dom_paa = find_dominating_aa_status (fbi, bb, index);
>> > +       if (dom_paa)
>> > +       *paa = *dom_paa;
>> > +       else
>> > +       paa->valid = true;
>> > +     }
>> > +
>> > +   return paa;
>> > + }
>> > +
>> >   /* Return true if a load from a formal parameter PARM_LOAD is known to retrieve
>> >      a value known not to be modified in this function before reaching the
>> > !    statement STMT.  FBI holds information about the function we have so far
>> > !    gathered but do not survive the summary building stage.  */
>> >
>> >   static bool
>> > ! parm_preserved_before_stmt_p (struct func_body_info *fbi, int index,
>> > !                             gimple stmt, tree parm_load)
>> >   {
>> > +   struct param_aa_status *paa;
>> >     bool modified = false;
>> >     ao_ref refd;
>> >
>> > !   /* FIXME: FBI can be NULL if we are being called from outside
>> > !      ipa_node_analysis or ipcp_transform_function, which currently happens
>> > !      during inlining analysis.  It would be great to extend fbi's lifetime and
>> > !      always have it.  Currently, we are just not afraid of too much walking in
>> > !      that case.  */
>> > !   if (fbi)
>> > !     {
>> > !       if (aa_overwalked (fbi))
>> > !       return false;
>> > !       paa = parm_bb_aa_status_for_bb (fbi, gimple_bb (stmt), index);
>> > !       if (paa->parm_modified)
>> > !       return false;
>> > !     }
>> > !   else
>> > !     paa = NULL;
>> >
>> >     gcc_checking_assert (gimple_vuse (stmt) != NULL_TREE);
>> >     ao_ref_init (&refd, parm_load);
>> > !   int walked = walk_aliased_vdefs (&refd, gimple_vuse (stmt), mark_modified,
>> > !                                  &modified, NULL);
>> > !   if (fbi)
>> > !     fbi->aa_walked += walked;
>> > !   if (paa && modified)
>> > !     paa->parm_modified = true;
>> >     return !modified;
>> >   }
>> >
>> > *************** parm_preserved_before_stmt_p (struct par
>> > *** 805,812 ****
>> >      modified.  Otherwise return -1.  */
>> >
>> >   static int
>> > ! load_from_unmodified_param (vec<ipa_param_descriptor> descriptors,
>> > !                           struct param_analysis_info *parms_ainfo,
>> >                             gimple stmt)
>> >   {
>> >     int index;
>> > --- 921,928 ----
>> >      modified.  Otherwise return -1.  */
>> >
>> >   static int
>> > ! load_from_unmodified_param (struct func_body_info *fbi,
>> > !                           vec<ipa_param_descriptor> descriptors,
>> >                             gimple stmt)
>> >   {
>> >     int index;
>> > *************** load_from_unmodified_param (vec<ipa_para
>> > *** 821,865 ****
>> >
>> >     index = ipa_get_param_decl_index_1 (descriptors, op1);
>> >     if (index < 0
>> > !       || !parm_preserved_before_stmt_p (parms_ainfo ? &parms_ainfo[index]
>> > !                                       : NULL, stmt, op1))
>> >       return -1;
>> >
>> >     return index;
>> >   }
>> >
>> > ! /* Return true if memory reference REF loads data that are known to be
>> > !    unmodified in this function before reaching statement STMT.  PARM_AINFO, if
>> > !    non-NULL, is a pointer to a structure containing temporary information about
>> > !    PARM.  */
>> >
>> >   static bool
>> > ! parm_ref_data_preserved_p (struct param_analysis_info *parm_ainfo,
>> > !                             gimple stmt, tree ref)
>> >   {
>> >     bool modified = false;
>> >     ao_ref refd;
>> >
>> > !   gcc_checking_assert (gimple_vuse (stmt));
>> > !   if (parm_ainfo && parm_ainfo->ref_modified)
>> > !     return false;
>> >
>> >     ao_ref_init (&refd, ref);
>> > !   walk_aliased_vdefs (&refd, gimple_vuse (stmt), mark_modified, &modified,
>> > !                     NULL);
>> > !   if (parm_ainfo && modified)
>> > !     parm_ainfo->ref_modified = true;
>> >     return !modified;
>> >   }
>> >
>> > ! /* Return true if the data pointed to by PARM is known to be unmodified in this
>> > !    function before reaching call statement CALL into which it is passed.
>> > !    PARM_AINFO is a pointer to a structure containing temporary information
>> > !    about PARM.  */
>> >
>> >   static bool
>> > ! parm_ref_data_pass_through_p (struct param_analysis_info *parm_ainfo,
>> > !                              gimple call, tree parm)
>> >   {
>> >     bool modified = false;
>> >     ao_ref refd;
>> > --- 937,995 ----
>> >
>> >     index = ipa_get_param_decl_index_1 (descriptors, op1);
>> >     if (index < 0
>> > !       || !parm_preserved_before_stmt_p (fbi, index, stmt, op1))
>> >       return -1;
>> >
>> >     return index;
>> >   }
>> >
>> > ! /* Return true if memory reference REF (which must be a load through parameter
>> > !    with INDEX) loads data that are known to be unmodified in this function
>> > !    before reaching statement STMT.  */
>> >
>> >   static bool
>> > ! parm_ref_data_preserved_p (struct func_body_info *fbi,
>> > !                          int index, gimple stmt, tree ref)
>> >   {
>> > +   struct param_aa_status *paa;
>> >     bool modified = false;
>> >     ao_ref refd;
>> >
>> > !   /* FIXME: FBI can be NULL if we are being called from outside
>> > !      ipa_node_analysis or ipcp_transform_function, which currently happens
>> > !      during inlining analysis.  It would be great to extend fbi's lifetime and
>> > !      always have it.  Currently, we are just not afraid of too much walking in
>> > !      that case.  */
>> > !   if (fbi)
>> > !     {
>> > !       if (aa_overwalked (fbi))
>> > !       return false;
>> > !       paa = parm_bb_aa_status_for_bb (fbi, gimple_bb (stmt), index);
>> > !       if (paa->ref_modified)
>> > !       return false;
>> > !     }
>> > !   else
>> > !     paa = NULL;
>> >
>> > +   gcc_checking_assert (gimple_vuse (stmt));
>> >     ao_ref_init (&refd, ref);
>> > !   int walked = walk_aliased_vdefs (&refd, gimple_vuse (stmt), mark_modified,
>> > !                                  &modified, NULL);
>> > !   if (fbi)
>> > !     fbi->aa_walked += walked;
>> > !   if (paa && modified)
>> > !     paa->ref_modified = true;
>> >     return !modified;
>> >   }
>> >
>> > ! /* Return true if the data pointed to by PARM (which is a parameter with INDEX)
>> > !    is known to be unmodified in this function before reaching call statement
>> > !    CALL into which it is passed.  PARM_AINFO is a pointer to a structure
>> > !    containing temporary information about PARM.  */
>> >
>> >   static bool
>> > ! parm_ref_data_pass_through_p (struct func_body_info *fbi, int index,
>> > !                             gimple call, tree parm)
>> >   {
>> >     bool modified = false;
>> >     ao_ref refd;
>> > *************** parm_ref_data_pass_through_p (struct par
>> > *** 868,884 ****
>> >        function because it is not goin to use it.  But do not cache the result
>> >        either.  Also, no such calculations for non-pointers.  */
>> >     if (!gimple_vuse (call)
>> > !       || !POINTER_TYPE_P (TREE_TYPE (parm)))
>> >       return false;
>> >
>> > !   if (parm_ainfo->pt_modified)
>> >       return false;
>> >
>> >     ao_ref_init_from_ptr_and_size (&refd, parm, NULL_TREE);
>> > !   walk_aliased_vdefs (&refd, gimple_vuse (call), mark_modified, &modified,
>> > !                     parm_ainfo ? &parm_ainfo->pt_visited_statements : NULL);
>> >     if (modified)
>> > !     parm_ainfo->pt_modified = true;
>> >     return !modified;
>> >   }
>> >
>> > --- 998,1018 ----
>> >        function because it is not goin to use it.  But do not cache the result
>> >        either.  Also, no such calculations for non-pointers.  */
>> >     if (!gimple_vuse (call)
>> > !       || !POINTER_TYPE_P (TREE_TYPE (parm))
>> > !       || aa_overwalked (fbi))
>> >       return false;
>> >
>> > !   struct param_aa_status *paa = parm_bb_aa_status_for_bb (fbi, gimple_bb (call),
>> > !                                                         index);
>> > !   if (paa->pt_modified)
>> >       return false;
>> >
>> >     ao_ref_init_from_ptr_and_size (&refd, parm, NULL_TREE);
>> > !   int walked = walk_aliased_vdefs (&refd, gimple_vuse (call), mark_modified,
>> > !                                  &modified, NULL);
>> > !   fbi->aa_walked += walked;
>> >     if (modified)
>> > !     paa->pt_modified = true;
>> >     return !modified;
>> >   }
>> >
>> > *************** parm_ref_data_pass_through_p (struct par
>> > *** 893,902 ****
>> >      reference respectively.  */
>> >
>> >   static bool
>> > ! ipa_load_from_parm_agg_1 (vec<ipa_param_descriptor> descriptors,
>> > !                         struct param_analysis_info *parms_ainfo, gimple stmt,
>> > !                         tree op, int *index_p, HOST_WIDE_INT *offset_p,
>> > !                         HOST_WIDE_INT *size_p, bool *by_ref_p)
>> >   {
>> >     int index;
>> >     HOST_WIDE_INT size, max_size;
>> > --- 1027,1037 ----
>> >      reference respectively.  */
>> >
>> >   static bool
>> > ! ipa_load_from_parm_agg_1 (struct func_body_info *fbi,
>> > !                         vec<ipa_param_descriptor> descriptors,
>> > !                         gimple stmt, tree op, int *index_p,
>> > !                         HOST_WIDE_INT *offset_p, HOST_WIDE_INT *size_p,
>> > !                         bool *by_ref_p)
>> >   {
>> >     int index;
>> >     HOST_WIDE_INT size, max_size;
>> > *************** ipa_load_from_parm_agg_1 (vec<ipa_param_
>> > *** 909,916 ****
>> >       {
>> >         int index = ipa_get_param_decl_index_1 (descriptors, base);
>> >         if (index >= 0
>> > !         && parm_preserved_before_stmt_p (parms_ainfo ? &parms_ainfo[index]
>> > !                                          : NULL, stmt, op))
>> >         {
>> >           *index_p = index;
>> >           *by_ref_p = false;
>> > --- 1044,1050 ----
>> >       {
>> >         int index = ipa_get_param_decl_index_1 (descriptors, base);
>> >         if (index >= 0
>> > !         && parm_preserved_before_stmt_p (fbi, index, stmt, op))
>> >         {
>> >           *index_p = index;
>> >           *by_ref_p = false;
>> > *************** ipa_load_from_parm_agg_1 (vec<ipa_param_
>> > *** 949,960 ****
>> >         */
>> >
>> >         gimple def = SSA_NAME_DEF_STMT (TREE_OPERAND (base, 0));
>> > !       index = load_from_unmodified_param (descriptors, parms_ainfo, def);
>> >       }
>> >
>> >     if (index >= 0
>> > !       && parm_ref_data_preserved_p (parms_ainfo ? &parms_ainfo[index] : NULL,
>> > !                                   stmt, op))
>> >       {
>> >         *index_p = index;
>> >         *by_ref_p = true;
>> > --- 1083,1093 ----
>> >         */
>> >
>> >         gimple def = SSA_NAME_DEF_STMT (TREE_OPERAND (base, 0));
>> > !       index = load_from_unmodified_param (fbi, descriptors, def);
>> >       }
>> >
>> >     if (index >= 0
>> > !       && parm_ref_data_preserved_p (fbi, index, stmt, op))
>> >       {
>> >         *index_p = index;
>> >         *by_ref_p = true;
>> > *************** ipa_load_from_parm_agg (struct ipa_node_
>> > *** 973,979 ****
>> >                         tree op, int *index_p, HOST_WIDE_INT *offset_p,
>> >                         bool *by_ref_p)
>> >   {
>> > !   return ipa_load_from_parm_agg_1 (info->descriptors, NULL, stmt, op, index_p,
>> >                                    offset_p, NULL, by_ref_p);
>> >   }
>> >
>> > --- 1106,1112 ----
>> >                         tree op, int *index_p, HOST_WIDE_INT *offset_p,
>> >                         bool *by_ref_p)
>> >   {
>> > !   return ipa_load_from_parm_agg_1 (NULL, info->descriptors, stmt, op, index_p,
>> >                                    offset_p, NULL, by_ref_p);
>> >   }
>> >
>> > *************** ipa_load_from_parm_agg (struct ipa_node_
>> > *** 1031,1038 ****
>> >      only needed for intraprocedural analysis.  */
>> >
>> >   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,
>> >                                   tree param_type)
>> > --- 1164,1171 ----
>> >      only needed for intraprocedural analysis.  */
>> >
>> >   static void
>> > ! compute_complex_assign_jump_func (struct func_body_info *fbi,
>> > !                                 struct ipa_node_params *info,
>> >                                   struct ipa_jump_func *jfunc,
>> >                                   gimple call, gimple stmt, tree name,
>> >                                   tree param_type)
>> > *************** compute_complex_assign_jump_func (struct
>> > *** 1048,1060 ****
>> >         if (SSA_NAME_IS_DEFAULT_DEF (op1))
>> >         index = ipa_get_param_decl_index (info, SSA_NAME_VAR (op1));
>> >         else
>> > !       index = load_from_unmodified_param (info->descriptors, parms_ainfo,
>> >                                             SSA_NAME_DEF_STMT (op1));
>> >         tc_ssa = op1;
>> >       }
>> >     else
>> >       {
>> > !       index = load_from_unmodified_param (info->descriptors, parms_ainfo, stmt);
>> >         tc_ssa = gimple_assign_lhs (stmt);
>> >       }
>> >
>> > --- 1181,1193 ----
>> >         if (SSA_NAME_IS_DEFAULT_DEF (op1))
>> >         index = ipa_get_param_decl_index (info, SSA_NAME_VAR (op1));
>> >         else
>> > !       index = load_from_unmodified_param (fbi, info->descriptors,
>> >                                             SSA_NAME_DEF_STMT (op1));
>> >         tc_ssa = op1;
>> >       }
>> >     else
>> >       {
>> > !       index = load_from_unmodified_param (fbi, info->descriptors, stmt);
>> >         tc_ssa = gimple_assign_lhs (stmt);
>> >       }
>> >
>> > *************** compute_complex_assign_jump_func (struct
>> > *** 1075,1082 ****
>> >         }
>> >         else if (gimple_assign_single_p (stmt))
>> >         {
>> > !         bool agg_p = parm_ref_data_pass_through_p (&parms_ainfo[index],
>> > !                                                    call, tc_ssa);
>> >           bool type_p = false;
>> >
>> >           if (param_type && POINTER_TYPE_P (param_type))
>> > --- 1208,1214 ----
>> >         }
>> >         else if (gimple_assign_single_p (stmt))
>> >         {
>> > !         bool agg_p = parm_ref_data_pass_through_p (fbi, index, call, tc_ssa);
>> >           bool type_p = false;
>> >
>> >           if (param_type && POINTER_TYPE_P (param_type))
>> > *************** compute_complex_assign_jump_func (struct
>> > *** 1115,1121 ****
>> >         if (type_p || jfunc->type == IPA_JF_UNKNOWN)
>> >         ipa_set_ancestor_jf (jfunc, offset,
>> >                              type_p ? TREE_TYPE (param_type) : NULL, index,
>> > !                            parm_ref_data_pass_through_p (&parms_ainfo[index],
>> >                                                            call, ssa), type_p);
>> >       }
>> >   }
>> > --- 1247,1253 ----
>> >         if (type_p || jfunc->type == IPA_JF_UNKNOWN)
>> >         ipa_set_ancestor_jf (jfunc, offset,
>> >                              type_p ? TREE_TYPE (param_type) : NULL, index,
>> > !                            parm_ref_data_pass_through_p (fbi, index,
>> >                                                            call, ssa), type_p);
>> >       }
>> >   }
>> > *************** get_ancestor_addr_info (gimple assign, t
>> > *** 1187,1194 ****
>> >        return D.1879_6;  */
>> >
>> >   static void
>> > ! compute_complex_ancestor_jump_func (struct ipa_node_params *info,
>> > !                                   struct param_analysis_info *parms_ainfo,
>> >                                     struct ipa_jump_func *jfunc,
>> >                                     gimple call, gimple phi, tree param_type)
>> >   {
>> > --- 1319,1326 ----
>> >        return D.1879_6;  */
>> >
>> >   static void
>> > ! compute_complex_ancestor_jump_func (struct func_body_info *fbi,
>> > !                                   struct ipa_node_params *info,
>> >                                     struct ipa_jump_func *jfunc,
>> >                                     gimple call, gimple phi, tree param_type)
>> >   {
>> > *************** compute_complex_ancestor_jump_func (stru
>> > *** 1247,1255 ****
>> >       type_p = !detect_type_change (obj, expr, TREE_TYPE (param_type),
>> >                                   call, jfunc, offset);
>> >     if (type_p || jfunc->type == IPA_JF_UNKNOWN)
>> > !     ipa_set_ancestor_jf (jfunc, offset, type_p ? TREE_TYPE (param_type) : NULL, index,
>> > !                        parm_ref_data_pass_through_p (&parms_ainfo[index],
>> > !                                                      call, parm), type_p);
>> >   }
>> >
>> >   /* Given OP which is passed as an actual argument to a called function,
>> > --- 1379,1388 ----
>> >       type_p = !detect_type_change (obj, expr, TREE_TYPE (param_type),
>> >                                   call, jfunc, offset);
>> >     if (type_p || jfunc->type == IPA_JF_UNKNOWN)
>> > !     ipa_set_ancestor_jf (jfunc, offset, type_p ? TREE_TYPE (param_type) : NULL,
>> > !                        index,
>> > !                        parm_ref_data_pass_through_p (fbi, index, call, parm),
>> > !                        type_p);
>> >   }
>> >
>> >   /* Given OP which is passed as an actual argument to a called function,
>> > *************** ipa_get_callee_param_type (struct cgraph
>> > *** 1594,1600 ****
>> >      to this callsite.  */
>> >
>> >   static void
>> > ! 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);
>> > --- 1727,1733 ----
>> >      to this callsite.  */
>> >
>> >   static void
>> > ! ipa_compute_jump_functions_for_edge (struct func_body_info *fbi,
>> >                                      struct cgraph_edge *cs)
>> >   {
>> >     struct ipa_node_params *info = IPA_NODE_REF (cs->caller);
>> > *************** ipa_compute_jump_functions_for_edge (str
>> > *** 1628,1634 ****
>> >           /* Aggregate passed by value, check for pass-through, otherwise we
>> >              will attempt to fill in aggregate contents later in this
>> >              for cycle.  */
>> > !         if (parm_preserved_before_stmt_p (&parms_ainfo[index], call, arg))
>> >             {
>> >               ipa_set_jf_simple_pass_through (jfunc, index, false, false);
>> >               continue;
>> > --- 1761,1767 ----
>> >           /* Aggregate passed by value, check for pass-through, otherwise we
>> >              will attempt to fill in aggregate contents later in this
>> >              for cycle.  */
>> > !         if (parm_preserved_before_stmt_p (fbi, index, call, arg))
>> >             {
>> >               ipa_set_jf_simple_pass_through (jfunc, index, false, false);
>> >               continue;
>> > *************** ipa_compute_jump_functions_for_edge (str
>> > *** 1642,1649 ****
>> >               if (index >= 0)
>> >                 {
>> >                   bool agg_p, type_p;
>> > !                 agg_p = parm_ref_data_pass_through_p (&parms_ainfo[index],
>> > !                                                       call, arg);
>> >                   if (param_type && POINTER_TYPE_P (param_type))
>> >                     type_p = !detect_type_change_ssa (arg, TREE_TYPE (param_type),
>> >                                                       call, jfunc);
>> > --- 1775,1781 ----
>> >               if (index >= 0)
>> >                 {
>> >                   bool agg_p, type_p;
>> > !                 agg_p = parm_ref_data_pass_through_p (fbi, index, call, arg);
>> >                   if (param_type && POINTER_TYPE_P (param_type))
>> >                     type_p = !detect_type_change_ssa (arg, TREE_TYPE (param_type),
>> >                                                       call, jfunc);
>> > *************** ipa_compute_jump_functions_for_edge (str
>> > *** 1658,1667 ****
>> >             {
>> >               gimple stmt = SSA_NAME_DEF_STMT (arg);
>> >               if (is_gimple_assign (stmt))
>> > !               compute_complex_assign_jump_func (info, parms_ainfo, jfunc,
>> >                                                   call, stmt, arg, param_type);
>> >               else if (gimple_code (stmt) == GIMPLE_PHI)
>> > !               compute_complex_ancestor_jump_func (info, parms_ainfo, jfunc,
>> >                                                     call, stmt, param_type);
>> >             }
>> >         }
>> > --- 1790,1799 ----
>> >             {
>> >               gimple stmt = SSA_NAME_DEF_STMT (arg);
>> >               if (is_gimple_assign (stmt))
>> > !               compute_complex_assign_jump_func (fbi, info, jfunc,
>> >                                                   call, stmt, arg, param_type);
>> >               else if (gimple_code (stmt) == GIMPLE_PHI)
>> > !               compute_complex_ancestor_jump_func (fbi, info, jfunc,
>> >                                                     call, stmt, param_type);
>> >             }
>> >         }
>> > *************** ipa_compute_jump_functions_for_edge (str
>> > *** 1692,1718 ****
>> >   }
>> >
>> >   /* Compute jump functions for all edges - both direct and indirect - outgoing
>> > !    from NODE.  Also count the actual arguments in the process.  */
>> >
>> >   static void
>> > ! ipa_compute_jump_functions (struct cgraph_node *node,
>> > !                           struct param_analysis_info *parms_ainfo)
>> >   {
>> >     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.  */
>> > !       if (!callee->definition && !flag_lto)
>> > !       continue;
>> > !       ipa_compute_jump_functions_for_edge (parms_ainfo, cs);
>> > !     }
>> >
>> > !   for (cs = node->indirect_calls; cs; cs = cs->next_callee)
>> > !     ipa_compute_jump_functions_for_edge (parms_ainfo, cs);
>> >   }
>> >
>> >   /* If STMT looks like a statement loading a value from a member pointer formal
>> > --- 1824,1852 ----
>> >   }
>> >
>> >   /* Compute jump functions for all edges - both direct and indirect - outgoing
>> > !    from BB.  */
>> >
>> >   static void
>> > ! ipa_compute_jump_functions_for_bb (struct func_body_info *fbi, basic_block bb)
>> >   {
>> > +   struct ipa_bb_info *bi = ipa_get_bb_info (fbi, bb);
>> > +   int i;
>> >     struct cgraph_edge *cs;
>> >
>> > !   FOR_EACH_VEC_ELT_REVERSE (bi->cg_edges, i, cs)
>> >       {
>> > !       struct cgraph_node *callee = cs->callee;
>> >
>> > !       if (callee)
>> > !       {
>> > !         cgraph_function_or_thunk_node (callee, NULL);
>> > !         /* We do not need to bother analyzing calls to unknown functions
>> > !            unless they may become known during lto/whopr.  */
>> > !         if (!callee->definition && !flag_lto)
>> > !           continue;
>> > !       }
>> > !       ipa_compute_jump_functions_for_edge (fbi, cs);
>> > !     }
>> >   }
>> >
>> >   /* If STMT looks like a statement loading a value from a member pointer formal
>> > *************** ipa_note_param_call (struct cgraph_node
>> > *** 1855,1891 ****
>> >      passed by value or reference.  */
>> >
>> >   static void
>> > ! ipa_analyze_indirect_call_uses (struct cgraph_node *node,
>> > !                               struct ipa_node_params *info,
>> > !                               struct param_analysis_info *parms_ainfo,
>> > !                               gimple call, tree target)
>> > ! {
>> > !   gimple def;
>> > !   tree n1, n2;
>> > !   gimple d1, d2;
>> > !   tree rec, rec2, cond;
>> > !   gimple branch;
>> > !   int index;
>> > !   basic_block bb, virt_bb, join;
>> >     HOST_WIDE_INT offset;
>> >     bool by_ref;
>> >
>> >     if (SSA_NAME_IS_DEFAULT_DEF (target))
>> >       {
>> >         tree var = SSA_NAME_VAR (target);
>> > !       index = ipa_get_param_decl_index (info, var);
>> >         if (index >= 0)
>> > !       ipa_note_param_call (node, index, call);
>> >         return;
>> >       }
>> >
>> > !   def = SSA_NAME_DEF_STMT (target);
>> >     if (gimple_assign_single_p (def)
>> > !       && ipa_load_from_parm_agg_1 (info->descriptors, parms_ainfo, def,
>> >                                    gimple_assign_rhs1 (def), &index, &offset,
>> >                                    NULL, &by_ref))
>> >       {
>> > !       struct cgraph_edge *cs = ipa_note_param_call (node, index, call);
>> >         if (cs->indirect_info->offset != offset)
>> >         cs->indirect_info->outer_type = NULL;
>> >         cs->indirect_info->offset = offset;
>> > --- 1989,2018 ----
>> >      passed by value or reference.  */
>> >
>> >   static void
>> > ! ipa_analyze_indirect_call_uses (struct func_body_info *fbi, gimple call,
>> > !                               tree target)
>> > ! {
>> > !   struct ipa_node_params *info = fbi->info;
>> >     HOST_WIDE_INT offset;
>> >     bool by_ref;
>> >
>> >     if (SSA_NAME_IS_DEFAULT_DEF (target))
>> >       {
>> >         tree var = SSA_NAME_VAR (target);
>> > !       int index = ipa_get_param_decl_index (info, var);
>> >         if (index >= 0)
>> > !       ipa_note_param_call (fbi->node, index, call);
>> >         return;
>> >       }
>> >
>> > !   int index;
>> > !   gimple def = SSA_NAME_DEF_STMT (target);
>> >     if (gimple_assign_single_p (def)
>> > !       && ipa_load_from_parm_agg_1 (fbi, info->descriptors, def,
>> >                                    gimple_assign_rhs1 (def), &index, &offset,
>> >                                    NULL, &by_ref))
>> >       {
>> > !       struct cgraph_edge *cs = ipa_note_param_call (fbi->node, index, call);
>> >         if (cs->indirect_info->offset != offset)
>> >         cs->indirect_info->outer_type = NULL;
>> >         cs->indirect_info->offset = offset;
>> > *************** ipa_analyze_indirect_call_uses (struct c
>> > *** 1904,1917 ****
>> >
>> >     /* First, we need to check whether one of these is a load from a member
>> >        pointer that is a parameter to this function. */
>> > !   n1 = PHI_ARG_DEF (def, 0);
>> > !   n2 = PHI_ARG_DEF (def, 1);
>> >     if (!ipa_is_ssa_with_stmt_def (n1) || !ipa_is_ssa_with_stmt_def (n2))
>> >       return;
>> > !   d1 = SSA_NAME_DEF_STMT (n1);
>> > !   d2 = SSA_NAME_DEF_STMT (n2);
>> >
>> > !   join = gimple_bb (def);
>> >     if ((rec = ipa_get_stmt_member_ptr_load_param (d1, false, &offset)))
>> >       {
>> >         if (ipa_get_stmt_member_ptr_load_param (d2, false, NULL))
>> > --- 2031,2046 ----
>> >
>> >     /* First, we need to check whether one of these is a load from a member
>> >        pointer that is a parameter to this function. */
>> > !   tree n1 = PHI_ARG_DEF (def, 0);
>> > !   tree n2 = PHI_ARG_DEF (def, 1);
>> >     if (!ipa_is_ssa_with_stmt_def (n1) || !ipa_is_ssa_with_stmt_def (n2))
>> >       return;
>> > !   gimple d1 = SSA_NAME_DEF_STMT (n1);
>> > !   gimple d2 = SSA_NAME_DEF_STMT (n2);
>> >
>> > !   tree rec;
>> > !   basic_block bb, virt_bb;
>> > !   basic_block join = gimple_bb (def);
>> >     if ((rec = ipa_get_stmt_member_ptr_load_param (d1, false, &offset)))
>> >       {
>> >         if (ipa_get_stmt_member_ptr_load_param (d2, false, NULL))
>> > *************** ipa_analyze_indirect_call_uses (struct c
>> > *** 1939,1945 ****
>> >     /* Third, let's see that the branching is done depending on the least
>> >        significant bit of the pfn. */
>> >
>> > !   branch = last_stmt (bb);
>> >     if (!branch || gimple_code (branch) != GIMPLE_COND)
>> >       return;
>> >
>> > --- 2068,2074 ----
>> >     /* Third, let's see that the branching is done depending on the least
>> >        significant bit of the pfn. */
>> >
>> > !   gimple branch = last_stmt (bb);
>> >     if (!branch || gimple_code (branch) != GIMPLE_COND)
>> >       return;
>> >
>> > *************** ipa_analyze_indirect_call_uses (struct c
>> > *** 1948,1954 ****
>> >         || !integer_zerop (gimple_cond_rhs (branch)))
>> >       return;
>> >
>> > !   cond = gimple_cond_lhs (branch);
>> >     if (!ipa_is_ssa_with_stmt_def (cond))
>> >       return;
>> >
>> > --- 2077,2083 ----
>> >         || !integer_zerop (gimple_cond_rhs (branch)))
>> >       return;
>> >
>> > !   tree cond = gimple_cond_lhs (branch);
>> >     if (!ipa_is_ssa_with_stmt_def (cond))
>> >       return;
>> >
>> > *************** ipa_analyze_indirect_call_uses (struct c
>> > *** 1973,1978 ****
>> > --- 2102,2108 ----
>> >         def = SSA_NAME_DEF_STMT (cond);
>> >       }
>> >
>> > +   tree rec2;
>> >     rec2 = ipa_get_stmt_member_ptr_load_param (def,
>> >                                              (TARGET_PTRMEMFUNC_VBIT_LOCATION
>> >                                               == ptrmemfunc_vbit_in_delta),
>> > *************** ipa_analyze_indirect_call_uses (struct c
>> > *** 1982,1990 ****
>> >
>> >     index = ipa_get_param_decl_index (info, rec);
>> >     if (index >= 0
>> > !       && parm_preserved_before_stmt_p (&parms_ainfo[index], call, rec))
>> >       {
>> > !       struct cgraph_edge *cs = ipa_note_param_call (node, index, call);
>> >         if (cs->indirect_info->offset != offset)
>> >         cs->indirect_info->outer_type = NULL;
>> >         cs->indirect_info->offset = offset;
>> > --- 2112,2120 ----
>> >
>> >     index = ipa_get_param_decl_index (info, rec);
>> >     if (index >= 0
>> > !       && parm_preserved_before_stmt_p (fbi, index, call, rec))
>> >       {
>> > !       struct cgraph_edge *cs = ipa_note_param_call (fbi->node, index, call);
>> >         if (cs->indirect_info->offset != offset)
>> >         cs->indirect_info->outer_type = NULL;
>> >         cs->indirect_info->offset = offset;
>> > *************** ipa_analyze_indirect_call_uses (struct c
>> > *** 1997,2012 ****
>> >
>> >   /* Analyze a CALL to an OBJ_TYPE_REF which is passed in TARGET and if the
>> >      object referenced in the expression is a formal parameter of the caller
>> > !    (described by INFO), create a call note for the statement. */
>> >
>> >   static void
>> > ! ipa_analyze_virtual_call_uses (struct cgraph_node *node,
>> > !                              struct ipa_node_params *info, gimple call,
>> > !                              tree target)
>> >   {
>> > -   struct cgraph_edge *cs;
>> > -   struct cgraph_indirect_call_info *ii;
>> > -   struct ipa_jump_func jfunc;
>> >     tree obj = OBJ_TYPE_REF_OBJECT (target);
>> >     int index;
>> >     HOST_WIDE_INT anc_offset;
>> > --- 2127,2139 ----
>> >
>> >   /* Analyze a CALL to an OBJ_TYPE_REF which is passed in TARGET and if the
>> >      object referenced in the expression is a formal parameter of the caller
>> > !    FBI->node (described by FBI->info), create a call note for the
>> > !    statement.  */
>> >
>> >   static void
>> > ! ipa_analyze_virtual_call_uses (struct func_body_info *fbi,
>> > !                              gimple call, tree target)
>> >   {
>> >     tree obj = OBJ_TYPE_REF_OBJECT (target);
>> >     int index;
>> >     HOST_WIDE_INT anc_offset;
>> > *************** ipa_analyze_virtual_call_uses (struct cg
>> > *** 2017,2024 ****
>> > --- 2144,2153 ----
>> >     if (TREE_CODE (obj) != SSA_NAME)
>> >       return;
>> >
>> > +   struct ipa_node_params *info = fbi->info;
>> >     if (SSA_NAME_IS_DEFAULT_DEF (obj))
>> >       {
>> > +       struct ipa_jump_func jfunc;
>> >         if (TREE_CODE (SSA_NAME_VAR (obj)) != PARM_DECL)
>> >         return;
>> >
>> > *************** ipa_analyze_virtual_call_uses (struct cg
>> > *** 2031,2036 ****
>> > --- 2160,2166 ----
>> >       }
>> >     else
>> >       {
>> > +       struct ipa_jump_func jfunc;
>> >         gimple stmt = SSA_NAME_DEF_STMT (obj);
>> >         tree expr;
>> >
>> > *************** ipa_analyze_virtual_call_uses (struct cg
>> > *** 2045,2052 ****
>> >         return;
>> >       }
>> >
>> > !   cs = ipa_note_param_call (node, index, call);
>> > !   ii = cs->indirect_info;
>> >     ii->offset = anc_offset;
>> >     ii->otr_token = tree_to_uhwi (OBJ_TYPE_REF_TOKEN (target));
>> >     ii->otr_type = obj_type_ref_class (target);
>> > --- 2175,2182 ----
>> >         return;
>> >       }
>> >
>> > !   struct cgraph_edge *cs = ipa_note_param_call (fbi->node, index, call);
>> > !   struct cgraph_indirect_call_info *ii = cs->indirect_info;
>> >     ii->offset = anc_offset;
>> >     ii->otr_token = tree_to_uhwi (OBJ_TYPE_REF_TOKEN (target));
>> >     ii->otr_type = obj_type_ref_class (target);
>> > *************** ipa_analyze_virtual_call_uses (struct cg
>> > *** 2058,2069 ****
>> >      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_ainfo, gimple call)
>> >   {
>> >     tree target = gimple_call_fn (call);
>> > -   struct cgraph_edge *cs;
>> >
>> >     if (!target
>> >         || (TREE_CODE (target) != SSA_NAME
>> > --- 2188,2196 ----
>> >      containing intermediate information about each formal parameter.  */
>> >
>> >   static void
>> > ! ipa_analyze_call_uses (struct func_body_info *fbi, gimple call)
>> >   {
>> >     tree target = gimple_call_fn (call);
>> >
>> >     if (!target
>> >         || (TREE_CODE (target) != SSA_NAME
>> > *************** ipa_analyze_call_uses (struct cgraph_nod
>> > *** 2072,2098 ****
>> >
>> >     /* If we previously turned the call into a direct call, there is
>> >        no need to analyze.  */
>> > !   cs = cgraph_edge (node, call);
>> >     if (cs && !cs->indirect_unknown_callee)
>> >       return;
>> >     if (TREE_CODE (target) == SSA_NAME)
>> > !     ipa_analyze_indirect_call_uses (node, info, parms_ainfo, call, target);
>> >     else if (virtual_method_call_p (target))
>> > !     ipa_analyze_virtual_call_uses (node, info, call, target);
>> >   }
>> >
>> >
>> >   /* 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_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,
>> > !                      struct param_analysis_info *parms_ainfo, gimple stmt)
>> >   {
>> >     if (is_gimple_call (stmt))
>> > !     ipa_analyze_call_uses (node, info, parms_ainfo, stmt);
>> >   }
>> >
>> >   /* Callback of walk_stmt_load_store_addr_ops for the visit_load.
>> > --- 2199,2223 ----
>> >
>> >     /* If we previously turned the call into a direct call, there is
>> >        no need to analyze.  */
>> > !   struct cgraph_edge *cs = cgraph_edge (fbi->node, call);
>> >     if (cs && !cs->indirect_unknown_callee)
>> >       return;
>> >     if (TREE_CODE (target) == SSA_NAME)
>> > !     ipa_analyze_indirect_call_uses (fbi, call, target);
>> >     else if (virtual_method_call_p (target))
>> > !     ipa_analyze_virtual_call_uses (fbi, call, target);
>> >   }
>> >
>> >
>> >   /* Analyze the call statement STMT with respect to formal parameters (described
>> > !    in INFO) of caller given by FBI->NODE.  Currently it only checks whether
>> > !    formal parameters are called.  */
>> >
>> >   static void
>> > ! ipa_analyze_stmt_uses (struct func_body_info *fbi, gimple stmt)
>> >   {
>> >     if (is_gimple_call (stmt))
>> > !     ipa_analyze_call_uses (fbi, stmt);
>> >   }
>> >
>> >   /* Callback of walk_stmt_load_store_addr_ops for the visit_load.
>> > *************** visit_ref_for_mod_analysis (gimple, tree
>> > *** 2116,2152 ****
>> >     return false;
>> >   }
>> >
>> > ! /* 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_AINFO is a pointer to a
>> > !    vector containing intermediate information about each formal parameter.   */
>> >
>> >   static void
>> > ! ipa_analyze_params_uses (struct cgraph_node *node,
>> > !                        struct param_analysis_info *parms_ainfo)
>> >   {
>> > -   tree decl = node->decl;
>> > -   basic_block bb;
>> > -   struct function *func;
>> >     gimple_stmt_iterator gsi;
>> > !   struct ipa_node_params *info = IPA_NODE_REF (node);
>> > !   int i;
>> >
>> > !   if (ipa_get_param_count (info) == 0 || info->uses_analysis_done)
>> > !     return;
>> >
>> > !   info->uses_analysis_done = 1;
>> > !   if (ipa_func_spec_opts_forbid_analysis_p (node))
>> > !     {
>> > !       for (i = 0; i < ipa_get_param_count (info); i++)
>> > !       {
>> > !         ipa_set_param_used (info, i, true);
>> > !         ipa_set_controlled_uses (info, i, IPA_UNDESCRIBED_USE);
>> > !       }
>> > !       return;
>> > !     }
>> >
>> > !   for (i = 0; i < ipa_get_param_count (info); i++)
>> >       {
>> >         tree parm = ipa_get_param (info, i);
>> >         int controlled_uses = 0;
>> > --- 2241,2283 ----
>> >     return false;
>> >   }
>> >
>> > ! /* Scan the statements in BB 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.  FBI holds various data about
>> > !    the function being analyzed.  */
>> >
>> >   static void
>> > ! ipa_analyze_params_uses_in_bb (struct func_body_info *fbi, basic_block bb)
>> >   {
>> >     gimple_stmt_iterator gsi;
>> > !   for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
>> > !     {
>> > !       gimple stmt = gsi_stmt (gsi);
>> >
>> > !       if (is_gimple_debug (stmt))
>> > !       continue;
>> >
>> > !       ipa_analyze_stmt_uses (fbi, stmt);
>> > !       walk_stmt_load_store_addr_ops (stmt, fbi->info,
>> > !                                    visit_ref_for_mod_analysis,
>> > !                                    visit_ref_for_mod_analysis,
>> > !                                    visit_ref_for_mod_analysis);
>> > !     }
>> > !   for (gsi = gsi_start_phis (bb); !gsi_end_p (gsi); gsi_next (&gsi))
>> > !     walk_stmt_load_store_addr_ops (gsi_stmt (gsi), fbi->info,
>> > !                                  visit_ref_for_mod_analysis,
>> > !                                  visit_ref_for_mod_analysis,
>> > !                                  visit_ref_for_mod_analysis);
>> > ! }
>> > !
>> > ! /* Calculate controlled uses of parameters of NODE.  */
>> > !
>> > ! static void
>> > ! ipa_analyze_controlled_uses (struct cgraph_node *node)
>> > ! {
>> > !   struct ipa_node_params *info = IPA_NODE_REF (node);
>> >
>> > !   for (int i = 0; i < ipa_get_param_count (info); i++)
>> >       {
>> >         tree parm = ipa_get_param (info, i);
>> >         int controlled_uses = 0;
>> > *************** ipa_analyze_params_uses (struct cgraph_n
>> > *** 2182,2226 ****
>> >         controlled_uses = IPA_UNDESCRIBED_USE;
>> >         ipa_set_controlled_uses (info, i, controlled_uses);
>> >       }
>> >
>> > !   func = DECL_STRUCT_FUNCTION (decl);
>> > !   FOR_EACH_BB_FN (bb, func)
>> > !     {
>> > !       for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
>> > !       {
>> > !         gimple stmt = gsi_stmt (gsi);
>> > !
>> > !         if (is_gimple_debug (stmt))
>> > !           continue;
>> >
>> > !         ipa_analyze_stmt_uses (node, info, parms_ainfo, stmt);
>> > !         walk_stmt_load_store_addr_ops (stmt, info,
>> > !                                        visit_ref_for_mod_analysis,
>> > !                                        visit_ref_for_mod_analysis,
>> > !                                        visit_ref_for_mod_analysis);
>> > !       }
>> > !       for (gsi = gsi_start_phis (bb); !gsi_end_p (gsi); gsi_next (&gsi))
>> > !       walk_stmt_load_store_addr_ops (gsi_stmt (gsi), info,
>> > !                                      visit_ref_for_mod_analysis,
>> > !                                      visit_ref_for_mod_analysis,
>> > !                                      visit_ref_for_mod_analysis);
>> > !     }
>> >   }
>> >
>> > ! /* Free stuff in PARMS_AINFO, assume there are PARAM_COUNT parameters.  */
>> >
>> > ! static void
>> > ! free_parms_ainfo (struct param_analysis_info *parms_ainfo, int param_count)
>> >   {
>> > !   int i;
>> >
>> > !   for (i = 0; i < param_count; i++)
>> > !     {
>> > !       if (parms_ainfo[i].parm_visited_statements)
>> > !       BITMAP_FREE (parms_ainfo[i].parm_visited_statements);
>> > !       if (parms_ainfo[i].pt_visited_statements)
>> > !       BITMAP_FREE (parms_ainfo[i].pt_visited_statements);
>> > !     }
>> >   }
>> >
>> >   /* Initialize the array describing properties of of formal parameters
>> > --- 2313,2348 ----
>> >         controlled_uses = IPA_UNDESCRIBED_USE;
>> >         ipa_set_controlled_uses (info, i, controlled_uses);
>> >       }
>> > + }
>> >
>> > ! /* Free stuff in BI.  */
>> >
>> > ! static void
>> > ! free_ipa_bb_info (struct ipa_bb_info *bi)
>> > ! {
>> > !   bi->cg_edges.release ();
>> > !   bi->paas.release ();
>> >   }
>> >
>> > ! /* Dominator walker driving the analysis.  */
>> >
>> > ! class analysis_dom_walker : public dom_walker
>> >   {
>> > ! public:
>> > !   analysis_dom_walker (struct func_body_info *fbi)
>> > !     : dom_walker (CDI_DOMINATORS), m_fbi (fbi) {}
>> >
>> > !   virtual void before_dom_children (basic_block);
>> > !
>> > ! private:
>> > !   struct func_body_info *m_fbi;
>> > ! };
>> > !
>> > ! void
>> > ! analysis_dom_walker::before_dom_children (basic_block bb)
>> > ! {
>> > !   ipa_analyze_params_uses_in_bb (m_fbi, bb);
>> > !   ipa_compute_jump_functions_for_bb (m_fbi, bb);
>> >   }
>> >
>> >   /* Initialize the array describing properties of of formal parameters
>> > *************** free_parms_ainfo (struct param_analysis_
>> > *** 2230,2253 ****
>> >   void
>> >   ipa_analyze_node (struct cgraph_node *node)
>> >   {
>> >     struct ipa_node_params *info;
>> > -   struct param_analysis_info *parms_ainfo;
>> > -   int param_count;
>> >
>> >     ipa_check_create_node_params ();
>> >     ipa_check_create_edge_args ();
>> >     info = IPA_NODE_REF (node);
>> > !   push_cfun (DECL_STRUCT_FUNCTION (node->decl));
>> >     ipa_initialize_node_params (node);
>> >
>> > !   param_count = ipa_get_param_count (info);
>> > !   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_ainfo);
>> > !   ipa_compute_jump_functions (node, parms_ainfo);
>> >
>> > !   free_parms_ainfo (parms_ainfo, param_count);
>> >     pop_cfun ();
>> >   }
>> >
>> > --- 2352,2411 ----
>> >   void
>> >   ipa_analyze_node (struct cgraph_node *node)
>> >   {
>> > +   struct func_body_info fbi;
>> >     struct ipa_node_params *info;
>> >
>> >     ipa_check_create_node_params ();
>> >     ipa_check_create_edge_args ();
>> >     info = IPA_NODE_REF (node);
>> > !
>> > !   if (info->analysis_done)
>> > !     return;
>> > !   info->analysis_done = 1;
>> > !
>> > !   if (ipa_func_spec_opts_forbid_analysis_p (node))
>> > !     {
>> > !       for (int i = 0; i < ipa_get_param_count (info); i++)
>> > !       {
>> > !         ipa_set_param_used (info, i, true);
>> > !         ipa_set_controlled_uses (info, i, IPA_UNDESCRIBED_USE);
>> > !       }
>> > !       return;
>> > !     }
>> > !
>> > !   struct function *func = DECL_STRUCT_FUNCTION (node->decl);
>> > !   push_cfun (func);
>> > !   calculate_dominance_info (CDI_DOMINATORS);
>> >     ipa_initialize_node_params (node);
>> > +   ipa_analyze_controlled_uses (node);
>> >
>> > !   fbi.node = node;
>> > !   fbi.info = IPA_NODE_REF (node);
>> > !   fbi.ibbis = vNULL;
>> > !   fbi.ibbis.safe_grow_cleared (last_basic_block_for_fn (cfun));
>> > !   fbi.param_count = ipa_get_param_count (info);
>> > !   fbi.aa_walked = 0;
>> >
>> > !   for (struct cgraph_edge *cs = node->callees; cs; cs = cs->next_callee)
>> > !     {
>> > !       ipa_bb_info *bi = ipa_get_bb_info (&fbi, gimple_bb (cs->call_stmt));
>> > !       bi->cg_edges.safe_push (cs);
>> > !     }
>> >
>> > !   for (struct cgraph_edge *cs = node->indirect_calls; cs; cs = cs->next_callee)
>> > !     {
>> > !       ipa_bb_info *bi = ipa_get_bb_info (&fbi, gimple_bb (cs->call_stmt));
>> > !       bi->cg_edges.safe_push (cs);
>> > !     }
>> > !
>> > !   analysis_dom_walker (&fbi).walk (ENTRY_BLOCK_PTR_FOR_FN (cfun));
>> > !
>> > !   int i;
>> > !   struct ipa_bb_info *bi;
>> > !   FOR_EACH_VEC_ELT (fbi.ibbis, i, bi)
>> > !     free_ipa_bb_info (bi);
>> > !   fbi.ibbis.release ();
>> > !   free_dominance_info (CDI_DOMINATORS);
>> >     pop_cfun ();
>> >   }
>> >
>> > *************** ipa_node_duplication_hook (struct cgraph
>> > *** 3299,3305 ****
>> >     new_info->lattices = NULL;
>> >     new_info->ipcp_orig_node = old_info->ipcp_orig_node;
>> >
>> > !   new_info->uses_analysis_done = old_info->uses_analysis_done;
>> >     new_info->node_enqueued = old_info->node_enqueued;
>> >
>> >     old_av = ipa_get_agg_replacements_for_node (src);
>> > --- 3457,3463 ----
>> >     new_info->lattices = NULL;
>> >     new_info->ipcp_orig_node = old_info->ipcp_orig_node;
>> >
>> > !   new_info->analysis_done = old_info->analysis_done;
>> >     new_info->node_enqueued = old_info->node_enqueued;
>> >
>> >     old_av = ipa_get_agg_replacements_for_node (src);
>> > *************** ipa_write_node_info (struct output_block
>> > *** 4424,4430 ****
>> >     for (j = 0; j < ipa_get_param_count (info); j++)
>> >       streamer_write_uhwi (ob, ipa_get_param_move_cost (info, j));
>> >     bp = bitpack_create (ob->main_stream);
>> > !   gcc_assert (info->uses_analysis_done
>> >               || ipa_get_param_count (info) == 0);
>> >     gcc_assert (!info->node_enqueued);
>> >     gcc_assert (!info->ipcp_orig_node);
>> > --- 4582,4588 ----
>> >     for (j = 0; j < ipa_get_param_count (info); j++)
>> >       streamer_write_uhwi (ob, ipa_get_param_move_cost (info, j));
>> >     bp = bitpack_create (ob->main_stream);
>> > !   gcc_assert (info->analysis_done
>> >               || ipa_get_param_count (info) == 0);
>> >     gcc_assert (!info->node_enqueued);
>> >     gcc_assert (!info->ipcp_orig_node);
>> > *************** ipa_read_node_info (struct lto_input_blo
>> > *** 4470,4476 ****
>> >
>> >     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++)
>> >       ipa_set_param_used (info, k, bp_unpack_value (&bp, 1));
>> > --- 4628,4634 ----
>> >
>> >     bp = streamer_read_bitpack (ib);
>> >     if (ipa_get_param_count (info) != 0)
>> > !     info->analysis_done = true;
>> >     info->node_enqueued = false;
>> >     for (k = 0; k < ipa_get_param_count (info); k++)
>> >       ipa_set_param_used (info, k, bp_unpack_value (&bp, 1));
>> > *************** adjust_agg_replacement_values (struct cg
>> > *** 4820,4836 ****
>> >       v->index = adj[v->index];
>> >   }
>> >
>> >
>> > ! /* Function body transformation phase.  */
>> >
>> >   unsigned int
>> >   ipcp_transform_function (struct cgraph_node *node)
>> >   {
>> >     vec<ipa_param_descriptor> descriptors = vNULL;
>> > !   struct param_analysis_info *parms_ainfo;
>> >     struct ipa_agg_replacement_value *aggval;
>> > -   gimple_stmt_iterator gsi;
>> > -   basic_block bb;
>> >     int param_count;
>> >     bool cfg_changed = false, something_changed = false;
>> >
>> > --- 4978,5106 ----
>> >       v->index = adj[v->index];
>> >   }
>> >
>> > + /* Dominator walker driving the ipcp modification phase.  */
>> > +
>> > + class ipcp_modif_dom_walker : public dom_walker
>> > + {
>> > + public:
>> > +   ipcp_modif_dom_walker (struct func_body_info *fbi,
>> > +                        vec<ipa_param_descriptor> descs,
>> > +                        struct ipa_agg_replacement_value *av,
>> > +                        bool *sc, bool *cc)
>> > +     : dom_walker (CDI_DOMINATORS), m_fbi (fbi), m_descriptors (descs),
>> > +       m_aggval (av), m_something_changed (sc), m_cfg_changed (cc) {}
>> > +
>> > +   virtual void before_dom_children (basic_block);
>> > +
>> > + private:
>> > +   struct func_body_info *m_fbi;
>> > +   vec<ipa_param_descriptor> m_descriptors;
>> > +   struct ipa_agg_replacement_value *m_aggval;
>> > +   bool *m_something_changed, *m_cfg_changed;
>> > + };
>> > +
>> > + void
>> > + ipcp_modif_dom_walker::before_dom_children (basic_block bb)
>> > + {
>> > +   gimple_stmt_iterator gsi;
>> > +   for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
>> > +     {
>> > +       struct ipa_agg_replacement_value *v;
>> > +       gimple stmt = gsi_stmt (gsi);
>> > +       tree rhs, val, t;
>> > +       HOST_WIDE_INT offset, size;
>> > +       int index;
>> > +       bool by_ref, vce;
>> > +
>> > +       if (!gimple_assign_load_p (stmt))
>> > +       continue;
>> > +       rhs = gimple_assign_rhs1 (stmt);
>> > +       if (!is_gimple_reg_type (TREE_TYPE (rhs)))
>> > +       continue;
>> >
>> > !       vce = false;
>> > !       t = rhs;
>> > !       while (handled_component_p (t))
>> > !       {
>> > !         /* V_C_E can do things like convert an array of integers to one
>> > !            bigger integer and similar things we do not handle below.  */
>> > !         if (TREE_CODE (rhs) == VIEW_CONVERT_EXPR)
>> > !           {
>> > !             vce = true;
>> > !             break;
>> > !           }
>> > !         t = TREE_OPERAND (t, 0);
>> > !       }
>> > !       if (vce)
>> > !       continue;
>> > !
>> > !       if (!ipa_load_from_parm_agg_1 (m_fbi, m_descriptors, stmt, rhs, &index,
>> > !                                    &offset, &size, &by_ref))
>> > !       continue;
>> > !       for (v = m_aggval; v; v = v->next)
>> > !       if (v->index == index
>> > !           && v->offset == offset)
>> > !         break;
>> > !       if (!v
>> > !         || v->by_ref != by_ref
>> > !         || tree_to_shwi (TYPE_SIZE (TREE_TYPE (v->value))) != size)
>> > !       continue;
>> > !
>> > !       gcc_checking_assert (is_gimple_ip_invariant (v->value));
>> > !       if (!useless_type_conversion_p (TREE_TYPE (rhs), TREE_TYPE (v->value)))
>> > !       {
>> > !         if (fold_convertible_p (TREE_TYPE (rhs), v->value))
>> > !           val = fold_build1 (NOP_EXPR, TREE_TYPE (rhs), v->value);
>> > !         else if (TYPE_SIZE (TREE_TYPE (rhs))
>> > !                  == TYPE_SIZE (TREE_TYPE (v->value)))
>> > !           val = fold_build1 (VIEW_CONVERT_EXPR, TREE_TYPE (rhs), v->value);
>> > !         else
>> > !           {
>> > !             if (dump_file)
>> > !               {
>> > !                 fprintf (dump_file, "    const ");
>> > !                 print_generic_expr (dump_file, v->value, 0);
>> > !                 fprintf (dump_file, "  can't be converted to type of ");
>> > !                 print_generic_expr (dump_file, rhs, 0);
>> > !                 fprintf (dump_file, "\n");
>> > !               }
>> > !             continue;
>> > !           }
>> > !       }
>> > !       else
>> > !       val = v->value;
>> > !
>> > !       if (dump_file && (dump_flags & TDF_DETAILS))
>> > !       {
>> > !         fprintf (dump_file, "Modifying stmt:\n  ");
>> > !         print_gimple_stmt (dump_file, stmt, 0, 0);
>> > !       }
>> > !       gimple_assign_set_rhs_from_tree (&gsi, val);
>> > !       update_stmt (stmt);
>> > !
>> > !       if (dump_file && (dump_flags & TDF_DETAILS))
>> > !       {
>> > !         fprintf (dump_file, "into:\n  ");
>> > !         print_gimple_stmt (dump_file, stmt, 0, 0);
>> > !         fprintf (dump_file, "\n");
>> > !       }
>> > !
>> > !       *m_something_changed = true;
>> > !       if (maybe_clean_eh_stmt (stmt)
>> > !         && gimple_purge_dead_eh_edges (gimple_bb (stmt)))
>> > !       *m_cfg_changed = true;
>> > !     }
>> > !
>> > ! }
>> > !
>> > ! /* IPCP transformation phase doing propagation of aggregate values.  */
>> >
>> >   unsigned int
>> >   ipcp_transform_function (struct cgraph_node *node)
>> >   {
>> >     vec<ipa_param_descriptor> descriptors = vNULL;
>> > !   struct func_body_info fbi;
>> >     struct ipa_agg_replacement_value *aggval;
>> >     int param_count;
>> >     bool cfg_changed = false, something_changed = false;
>> >
>> > *************** ipcp_transform_function (struct cgraph_n
>> > *** 4850,4951 ****
>> >     adjust_agg_replacement_values (node, aggval);
>> >     if (dump_file)
>> >       ipa_dump_agg_replacement_values (dump_file, aggval);
>> > -   parms_ainfo = XALLOCAVEC (struct param_analysis_info, param_count);
>> > -   memset (parms_ainfo, 0, sizeof (struct param_analysis_info) * param_count);
>> > -   descriptors.safe_grow_cleared (param_count);
>> > -   ipa_populate_param_decls (node, descriptors);
>> > -
>> > -   FOR_EACH_BB_FN (bb, cfun)
>> > -     for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
>> > -       {
>> > -       struct ipa_agg_replacement_value *v;
>> > -       gimple stmt = gsi_stmt (gsi);
>> > -       tree rhs, val, t;
>> > -       HOST_WIDE_INT offset, size;
>> > -       int index;
>> > -       bool by_ref, vce;
>> > -
>> > -       if (!gimple_assign_load_p (stmt))
>> > -         continue;
>> > -       rhs = gimple_assign_rhs1 (stmt);
>> > -       if (!is_gimple_reg_type (TREE_TYPE (rhs)))
>> > -         continue;
>> > -
>> > -       vce = false;
>> > -       t = rhs;
>> > -       while (handled_component_p (t))
>> > -         {
>> > -           /* V_C_E can do things like convert an array of integers to one
>> > -                bigger integer and similar things we do not handle below.  */
>> > -             if (TREE_CODE (rhs) == VIEW_CONVERT_EXPR)
>> > -             {
>> > -               vce = true;
>> > -               break;
>> > -             }
>> > -           t = TREE_OPERAND (t, 0);
>> > -         }
>> > -       if (vce)
>> > -         continue;
>> >
>> > !       if (!ipa_load_from_parm_agg_1 (descriptors, parms_ainfo, stmt,
>> > !                                      rhs, &index, &offset, &size, &by_ref))
>> > !         continue;
>> > !       for (v = aggval; v; v = v->next)
>> > !         if (v->index == index
>> > !             && v->offset == offset)
>> > !           break;
>> > !       if (!v
>> > !           || v->by_ref != by_ref
>> > !           || tree_to_shwi (TYPE_SIZE (TREE_TYPE (v->value))) != size)
>> > !         continue;
>> >
>> > !       gcc_checking_assert (is_gimple_ip_invariant (v->value));
>> > !       if (!useless_type_conversion_p (TREE_TYPE (rhs), TREE_TYPE (v->value)))
>> > !         {
>> > !           if (fold_convertible_p (TREE_TYPE (rhs), v->value))
>> > !             val = fold_build1 (NOP_EXPR, TREE_TYPE (rhs), v->value);
>> > !           else if (TYPE_SIZE (TREE_TYPE (rhs))
>> > !                    == TYPE_SIZE (TREE_TYPE (v->value)))
>> > !             val = fold_build1 (VIEW_CONVERT_EXPR, TREE_TYPE (rhs), v->value);
>> > !           else
>> > !             {
>> > !               if (dump_file)
>> > !                 {
>> > !                   fprintf (dump_file, "    const ");
>> > !                   print_generic_expr (dump_file, v->value, 0);
>> > !                   fprintf (dump_file, "  can't be converted to type of ");
>> > !                   print_generic_expr (dump_file, rhs, 0);
>> > !                   fprintf (dump_file, "\n");
>> > !                 }
>> > !               continue;
>> > !             }
>> > !         }
>> > !       else
>> > !         val = v->value;
>> > !
>> > !       if (dump_file && (dump_flags & TDF_DETAILS))
>> > !         {
>> > !           fprintf (dump_file, "Modifying stmt:\n  ");
>> > !           print_gimple_stmt (dump_file, stmt, 0, 0);
>> > !         }
>> > !       gimple_assign_set_rhs_from_tree (&gsi, val);
>> > !       update_stmt (stmt);
>> > !
>> > !       if (dump_file && (dump_flags & TDF_DETAILS))
>> > !         {
>> > !           fprintf (dump_file, "into:\n  ");
>> > !           print_gimple_stmt (dump_file, stmt, 0, 0);
>> > !           fprintf (dump_file, "\n");
>> > !         }
>> > !
>> > !       something_changed = true;
>> > !       if (maybe_clean_eh_stmt (stmt)
>> > !           && gimple_purge_dead_eh_edges (gimple_bb (stmt)))
>> > !         cfg_changed = true;
>> > !       }
>> >
>> >     (*ipa_node_agg_replacements)[node->uid] = NULL;
>> > -   free_parms_ainfo (parms_ainfo, param_count);
>> >     descriptors.release ();
>> >
>> >     if (!something_changed)
>> > --- 5120,5146 ----
>> >     adjust_agg_replacement_values (node, aggval);
>> >     if (dump_file)
>> >       ipa_dump_agg_replacement_values (dump_file, aggval);
>> >
>> > !   fbi.node = node;
>> > !   fbi.info = NULL;
>> > !   fbi.ibbis = vNULL;
>> > !   fbi.ibbis.safe_grow_cleared (last_basic_block_for_fn (cfun));
>> > !   fbi.param_count = param_count;
>> > !   fbi.aa_walked = 0;
>> >
>> > !   descriptors.safe_grow_cleared (param_count);
>> > !   ipa_populate_param_decls (node, descriptors);
>> > !   calculate_dominance_info (CDI_DOMINATORS);
>> > !   ipcp_modif_dom_walker (&fbi, descriptors, aggval, &something_changed,
>> > !                        &cfg_changed).walk (ENTRY_BLOCK_PTR_FOR_FN (cfun));
>> >
>> > +   int i;
>> > +   struct ipa_bb_info *bi;
>> > +   FOR_EACH_VEC_ELT (fbi.ibbis, i, bi)
>> > +     free_ipa_bb_info (bi);
>> > +   fbi.ibbis.release ();
>> > +   free_dominance_info (CDI_DOMINATORS);
>> >     (*ipa_node_agg_replacements)[node->uid] = NULL;
>> >     descriptors.release ();
>> >
>> >     if (!something_changed)
>> > Index: src/gcc/ipa-prop.h
>> > ===================================================================
>> > *** src.orig/gcc/ipa-prop.h
>> > --- src/gcc/ipa-prop.h
>> > *************** struct ipa_node_params
>> > *** 371,378 ****
>> >     /* If this node is an ipa-cp clone, these are the known values that describe
>> >        what it has been specialized for.  */
>> >     vec<tree> known_vals;
>> > !   /* Whether the param uses analysis has already been performed.  */
>> > !   unsigned uses_analysis_done : 1;
>> >     /* Whether the function is enqueued in ipa-cp propagation stack.  */
>> >     unsigned node_enqueued : 1;
>> >     /* Whether we should create a specialized version based on values that are
>> > --- 371,379 ----
>> >     /* If this node is an ipa-cp clone, these are the known values that describe
>> >        what it has been specialized for.  */
>> >     vec<tree> known_vals;
>> > !   /* Whether the param uses analysis and jump function computation has already
>> > !      been performed.  */
>> > !   unsigned analysis_done : 1;
>> >     /* Whether the function is enqueued in ipa-cp propagation stack.  */
>> >     unsigned node_enqueued : 1;
>> >     /* Whether we should create a specialized version based on values that are
>> > Index: src/gcc/params.def
>> > ===================================================================
>> > *** src.orig/gcc/params.def
>> > --- src/gcc/params.def
>> > *************** DEFPARAM (PARAM_IPA_MAX_AGG_ITEMS,
>> > *** 947,952 ****
>> > --- 947,958 ----
>> >           "jump functions and lattices",
>> >           16, 0, 0)
>> >
>> > + DEFPARAM (PARAM_IPA_MAX_AA_STEPS,
>> > +         "ipa-max-aa-steps",
>> > +         "Maximum number of statements that will be visited by IPA formal "
>> > +         "parameter analysis based on alias analysis in any given function",
>> > +         100000, 0, 0)
>> > +
>> >   DEFPARAM (PARAM_IPA_CP_LOOP_HINT_BONUS,
>> >           "ipa-cp-loop-hint-bonus",
>> >           "Compile-time bonus IPA-CP assigns to candidates which make loop "
>> >

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH] Make ipa-prop analyze BBs in DOM order
  2014-04-25 15:30 [PATCH] Make ipa-prop analyze BBs in DOM order Martin Jambor
  2014-04-28  9:05 ` Richard Biener
@ 2014-05-15 18:42 ` Jan Hubicka
  1 sibling, 0 replies; 5+ messages in thread
From: Jan Hubicka @ 2014-05-15 18:42 UTC (permalink / raw)
  To: GCC Patches, Jan Hubicka

> Hi,
> 
> the following patch deals with requested propagation in PR 53787 in
> the real benchmark (as opposed to the original simple testcase) by
> analyzing individual BBs in ipa-prop.c in dominator order.
> 
> Currently we do the analysis in two loops, in the first the order is
> given by FOR_EACH_BB_FN and in the second the order is the order of
> call graph edges (which in practice is quite bad because we tend to
> start with BBs towards the end).  When analysis determines that a
> non-SSA parameter or that data pointed to by a parameter are modified,
> this is marked into a function wide flag (describing the parameter)
> and we always consider the data clobbered from that moment on in order
> to save AA walking.
> 
> This patch changes the analysis into dominator order and data is
> considered clobbered only in dominator children of a block where it
> was determined to be possibly clobbered, not in the whole function.
> This was confirmed to help in the aforementioned PR.
> 
> The patch also, enforces a cap on the number of statements walked
> (approx. 4 times the highest I have ever seen).  On the other hand it
> gives up trying to cache the bitmap of visited memory-SSAs.  The
> per-BB information had to be put somewhere and I took this opportunity
> to cram a lot of commonly used per-function data into the same
> structure, which is then passed among various functions.  The new
> structure replaces the struct param_analysis_info.
> 
> Bootstrapped and tested on x86_64-linux, I have also LTO-built Firefox
> at -O3 with it.  OK for trunk?
> 
> Thanks,
> 
> Martin
> 
> 
> 2014-02-12  Martin Jambor  <mjambor@suse.cz>
> 
> 	PR tree-optimization/53787
> 	* params.def (PARAM_IPA_CP_LOOP_HINT_BONUS): New param.
> 	* ipa-prop.h (ipa_node_params): Rename uses_analysis_done to
> 	analysis_done, update all uses.
> 	* ipa-prop.c: Include domwalk.h
> 	(param_analysis_info): Removed.
> 	(param_aa_status): New type.
> 	(ipa_bb_info): Likewise.
> 	(func_body_info): Likewise.
> 	(ipa_get_bb_info): New function.
> 	(aa_overwalked): Likewise.
> 	(find_dominating_aa_status): Likewise.
> 	(parm_bb_aa_status_for_bb): Likewise.
> 	(parm_preserved_before_stmt_p): Changed to use new param AA info.
> 	(load_from_unmodified_param): Accept func_body_info as a parameter
> 	instead of parms_ainfo.
> 	(parm_ref_data_preserved_p): Changed to use new param AA info.
> 	(parm_ref_data_pass_through_p): Likewise.
> 	(ipa_load_from_parm_agg_1): Likewise.  Update callers.
> 	(compute_complex_assign_jump_func): Changed to use new param AA info.
> 	(compute_complex_ancestor_jump_func): Likewise.
> 	(ipa_compute_jump_functions_for_edge): Likewise.
> 	(ipa_compute_jump_functions): Removed.
> 	(ipa_compute_jump_functions_for_bb): New function.
> 	(ipa_analyze_indirect_call_uses): Likewise, moved variable
> 	declarations down.
> 	(ipa_analyze_virtual_call_uses): Accept func_body_info instead of node
> 	and info, moved variable declarations down.
> 	(ipa_analyze_call_uses): Accept and pass on func_body_info instead of
> 	node and info.
> 	(ipa_analyze_stmt_uses): Likewise.
> 	(ipa_analyze_params_uses): Removed.
> 	(ipa_analyze_params_uses_in_bb): New function.
> 	(ipa_analyze_controlled_uses): Likewise.
> 	(free_ipa_bb_info): Likewise.
> 	(analysis_dom_walker): New class.
> 	(ipa_analyze_node): Handle node-specific forbidden analysis,
> 	initialize and free func_body_info, use dominator walker.
> 	(ipcp_modif_dom_walker): New class.
> 	(ipcp_transform_function): Create and free func_body_info, use
> 	ipcp_modif_dom_walker, moved a lot of functionality there.

> 
> --- 59,111 ----
>   #include "ipa-utils.h"
>   #include "stringpool.h"
>   #include "tree-ssanames.h"
> + #include "domwalk.h"
>   
> ! /* Intermediate information that we get from AA analysis about a parameter.  */

AA is alias analysis, so I guess either "AA" (removing analysis) or "alias analysis" :)

>   
> ! struct param_aa_status
>   {
> +   /* If not true, look at the dominator parent instead.  */
> +   bool valid;

In isolation, this comment is hardly understandable.
Perhaps you can mention that this info is used for each parameter during the
dominator order propagation.


> + 
> +   /* Whether we have seen something which might have modified the data in
> +      question.  Parm is for the parameter itself, ref is for data it points to
> +      but using the alias type of individual accesses and pt is the same thing
> +      but for computing aggregate pass-through functions using a very inclusive
> +      ao_ref.  */

I guess PARM/REF/PR per coding style ;))

> ! 
> ! /* Structure with global information that is only used when looking at function
> !    body. */
> ! 
> ! struct func_body_info
> ! {
> !   /* The node that is being analyzed.  */
> !   cgraph_node *node;
> ! 
> !   /* Its info.  */
> !   struct ipa_node_params *info;
> ! 
> !   /* Information about individual BBs. */
> !   vec<ipa_bb_info> ibbis;

I would keep vector name same with accestor, it is called bb_info, so perhaps bb_infos?
ibbis is funny name (same of paas above ;)

> !   /* FIXME: FBI can be NULL if we are being called from outside
> !      ipa_node_analysis or ipcp_transform_function, which currently happens
> !      during inlining analysis.  It would be great to extend fbi's lifetime and
> !      always have it.  Currently, we are just not afraid of too much walking in
> !      that case.  */

Yep, how much info do we really test in ipa-inline?
I suppose we can hook the info into the jump functions we remember, but not stream it for LTO
since it is pointless without the function body...

> *************** parm_ref_data_pass_through_p (struct par
> *** 893,902 ****
>      reference respectively.  */

Probably you want to update comment for new params.
> Index: src/gcc/params.def
> ===================================================================
> *** src.orig/gcc/params.def
> --- src/gcc/params.def
> *************** DEFPARAM (PARAM_IPA_MAX_AGG_ITEMS,
> *** 947,952 ****
> --- 947,958 ----
>   	  "jump functions and lattices",
>   	  16, 0, 0)
>   
> + DEFPARAM (PARAM_IPA_MAX_AA_STEPS,
> + 	  "ipa-max-aa-steps",
> + 	  "Maximum number of statements that will be visited by IPA formal "
> + 	  "parameter analysis based on alias analysis in any given function",
> + 	  100000, 0, 0)
> + 
>   DEFPARAM (PARAM_IPA_CP_LOOP_HINT_BONUS,
>   	  "ipa-cp-loop-hint-bonus",
>   	  "Compile-time bonus IPA-CP assigns to candidates which make loop "

Probably you need also invoke.texi update.

OK with these changes.
Thanks,
Honza

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2014-05-15 18:42 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-04-25 15:30 [PATCH] Make ipa-prop analyze BBs in DOM order Martin Jambor
2014-04-28  9:05 ` Richard Biener
2014-04-28 10:06   ` Martin Jambor
2014-04-28 11:44     ` Richard Biener
2014-05-15 18:42 ` Jan Hubicka

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).