From: Richard Biener <richard.guenther@gmail.com>
To: GCC Patches <gcc-patches@gcc.gnu.org>, Jan Hubicka <hubicka@ucw.cz>
Subject: Re: [PATCH] Make ipa-prop analyze BBs in DOM order
Date: Mon, 28 Apr 2014 09:05:00 -0000 [thread overview]
Message-ID: <CAFiYyc0=OGF72go59MG0Heov=zzzwTCQJkyqcdLrwWLhgAFCrQ@mail.gmail.com> (raw)
In-Reply-To: <20140425151200.GH12215@virgil.suse>
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 "
>
next prev parent reply other threads:[~2014-04-28 9:01 UTC|newest]
Thread overview: 5+ messages / expand[flat|nested] mbox.gz Atom feed top
2014-04-25 15:30 Martin Jambor
2014-04-28 9:05 ` Richard Biener [this message]
2014-04-28 10:06 ` Martin Jambor
2014-04-28 11:44 ` Richard Biener
2014-05-15 18:42 ` Jan Hubicka
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to='CAFiYyc0=OGF72go59MG0Heov=zzzwTCQJkyqcdLrwWLhgAFCrQ@mail.gmail.com' \
--to=richard.guenther@gmail.com \
--cc=gcc-patches@gcc.gnu.org \
--cc=hubicka@ucw.cz \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
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).