From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 15717 invoked by alias); 28 Apr 2014 09:01:54 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Received: (qmail 15699 invoked by uid 89); 28 Apr 2014 09:01:53 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-0.5 required=5.0 tests=AWL,BAYES_20,FREEMAIL_FROM,RCVD_IN_DNSWL_LOW,SPF_PASS autolearn=ham version=3.3.2 X-HELO: mail-we0-f174.google.com Received: from mail-we0-f174.google.com (HELO mail-we0-f174.google.com) (74.125.82.174) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with (AES128-SHA encrypted) ESMTPS; Mon, 28 Apr 2014 09:01:48 +0000 Received: by mail-we0-f174.google.com with SMTP id w62so4855756wes.33 for ; Mon, 28 Apr 2014 02:01:45 -0700 (PDT) MIME-Version: 1.0 X-Received: by 10.180.78.5 with SMTP id x5mr14549553wiw.12.1398675705200; Mon, 28 Apr 2014 02:01:45 -0700 (PDT) Received: by 10.194.185.180 with HTTP; Mon, 28 Apr 2014 02:01:45 -0700 (PDT) In-Reply-To: <20140425151200.GH12215@virgil.suse> References: <20140425151200.GH12215@virgil.suse> Date: Mon, 28 Apr 2014 09:05:00 -0000 Message-ID: Subject: Re: [PATCH] Make ipa-prop analyze BBs in DOM order From: Richard Biener To: GCC Patches , Jan Hubicka Content-Type: text/plain; charset=UTF-8 X-IsSubscribed: yes X-SW-Source: 2014-04/txt/msg01822.txt.bz2 On Fri, Apr 25, 2014 at 5:12 PM, Martin Jambor 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 > > 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 cg_edges; > ! /* Alias analysis statuses of each formal parameter at this bb. */ > ! vec 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 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 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 descriptors, > gimple stmt) > { > int index; > *************** load_from_unmodified_param (vec *** 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 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 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 *** 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 *** 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 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 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 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 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 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 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 " >