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

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).