This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [PATCH] Make ipa-prop analyze BBs in DOM order


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 "
>


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]