From patchwork Thu Jun 24 23:05:27 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Martin Jambor X-Patchwork-Id: 56869 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) by ozlabs.org (Postfix) with SMTP id 34742B7083 for ; Fri, 25 Jun 2010 09:02:40 +1000 (EST) Received: (qmail 21184 invoked by alias); 24 Jun 2010 23:02:37 -0000 Received: (qmail 20196 invoked by uid 22791); 24 Jun 2010 23:02:33 -0000 X-SWARE-Spam-Status: No, hits=-6.2 required=5.0 tests=AWL, BAYES_00, RCVD_IN_DNSWL_HI, TW_DN, TW_SV, TW_TM X-Spam-Check-By: sourceware.org Received: from cantor.suse.de (HELO mx1.suse.de) (195.135.220.2) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Thu, 24 Jun 2010 23:02:21 +0000 Received: from relay1.suse.de (charybdis-ext.suse.de [195.135.221.2]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.suse.de (Postfix) with ESMTP id 3CDB393F19; Fri, 25 Jun 2010 01:02:18 +0200 (CEST) Date: Fri, 25 Jun 2010 01:05:27 +0200 From: Martin Jambor To: Richard Guenther Cc: GCC Patches , Jan Hubicka Subject: Re: [PATCH 2/2] Replace the modified flag with AA-queries Message-ID: <20100624230526.GB2773@alvy.suse.cz> Mail-Followup-To: Richard Guenther , GCC Patches , Jan Hubicka References: <20100621095420.256789766@virgil.suse.cz> <20100621095442.846731128@virgil.suse.cz> MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: User-Agent: Mutt/1.5.20 (2009-06-14) X-IsSubscribed: yes Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org Hi, On Mon, Jun 21, 2010 at 02:21:41PM +0200, Richard Guenther wrote: > On Mon, 21 Jun 2010, Richard Guenther wrote: > > > On Mon, 21 Jun 2010, Martin Jambor wrote: > > > > > Hi, > > > > > > indirect inlining was written before we had AA-info at our disposal in > > > the "early" passes and so when confronted with the necessity to > > > guarantee that a member pointer parameter was not changed before it > > > was used I have resorted to requiring it is never modified in the > > > whole function. > > > > > > With alias analysis information this is no longer necessary. This > > > code therefore does away with the flag and uses AA instead. To big > > > extent I have copied the clobbering identification code from IPA-SRA > > > and hope I got it correct. > > > > > > I added a new testcase checking that we so not indirect-inline when we > > > shouldn't because a member-pointer parameter is modified before being > > > passed on. > > > > > > I am aware that there are no hunks removing testcase > > > gcc.dg/ipa/modif-1.c in the patch, that is because I generate my > > > patches with quilt rather than svn. I will remember to svn-delete the > > > file. > > > > > > I have bootstrapped and tested this patch (on top of the previous one) > > > on x86_64-linux without any issues, OK for trunk? > > > > > > Thanks, > > > > > > Martin > > > > > > > > > 2010-06-18 Martin Jambor > > > > > > * ipa-prop.h (struct ipa_param_descriptor): Remove the modified flag. > > > (ipa_is_param_modified): Removed. > > > * ipa-prop.c (visit_store_addr_for_mod_analysis): Do not set the > > > modified flag. > > > (mark_modified): New function. > > > (is_parm_modified_at_call): Likewise. > > > (compute_pass_through_member_ptrs): Use is_parm_modified_at_call > > > instead of ipa_is_param_modified. > > > (ipa_analyze_indirect_call_uses): Likewise. > > > (ipa_print_node_params): Do not dump the modified flag. > > > (ipa_write_node_info): Do not stream the modified flag. > > > (ipa_read_node_info): Likewise. > > > > > > * testsuite/g++.dg/ipa/iinline-2.C: New test. > > > * testsuite/gcc.dg/ipa/modif-1.c: Removed. > > > > > > Index: icln/gcc/ipa-prop.c > > > =================================================================== > > > --- icln.orig/gcc/ipa-prop.c 2010-06-20 18:23:13.000000000 +0200 > > > +++ icln/gcc/ipa-prop.c 2010-06-20 18:24:32.000000000 +0200 > > > @@ -212,7 +212,6 @@ visit_store_addr_for_mod_analysis (gimpl > > > { > > > int index = ipa_get_param_decl_index (info, op); > > > gcc_assert (index >= 0); > > > - info->params[index].modified = true; > > > info->params[index].used = true; > > > } > > > > > > @@ -707,6 +706,34 @@ type_like_member_ptr_p (tree type, tree > > > return true; > > > } > > > > > > +/* Callback of walk_aliased_vdefs. Flags that it has been invoked to the > > > + boolean variable pointed to by DATA. */ > > > + > > > +static bool > > > +mark_modified (ao_ref *ao ATTRIBUTE_UNUSED, tree vdef ATTRIBUTE_UNUSED, > > > + void *data) > > > +{ > > > + bool *b = (bool *) data; > > > + *b = true; > > > + return true; > > > +} > > > + > > > +/* Return true if the formal parameter PARM might have been modified in this > > > + function before reaching the statement CALL. */ > > > + > > > +static bool > > > +is_parm_modified_at_call (gimple call, tree parm) > > > +{ > > > + bool modified = false; > > > + ao_ref refd; > > > + > > > + ao_ref_init (&refd, parm); > > > + walk_aliased_vdefs (&refd, gimple_vuse (call), mark_modified, > > > + &modified, NULL); > > > + > > > + return modified; > > > +} > > > + > > > /* Go through arguments of the CALL and for every one that looks like a member > > > pointer, check whether it can be safely declared pass-through and if so, > > > mark that to the corresponding item of jump FUNCTIONS. Return true iff > > > @@ -733,7 +760,7 @@ compute_pass_through_member_ptrs (struct > > > int index = ipa_get_param_decl_index (info, arg); > > > > > > gcc_assert (index >=0); > > > - if (!ipa_is_param_modified (info, index)) > > > + if (!is_parm_modified_at_call (call, arg)) > > > > Hm, I do not understand this. Do you just want to ask whether > > arg is modified _by_ the call? Or do you want to know whether > > arg is modified on any path leading from function entry to > > the call (which is what you implement)? In that case I suggest > > a better name for the function, like is_parm_modified_before_call. OK, I have renamed the function, among other things. > > > > Note that you are not implementing any kind of limiting, doing many > > of these walk can be very expensive. Right, I wanted to start with something simple but limiting should be done. > > For example in the above loop > > I'd first check whether arg is a PARM_DECL before checking > > type_like_member_ptr_p. In compute_pass_through_member_ptrs, the result of type_like_member_ptr_p is then used to determine whether we will scan for constant member pointer arguments, hoping that most of the time we won't. > > And you can use one caching bitmap > > per PARM_DECL for the visited parms to walk_aliased_vdefs which > > will bound complexity to number of cfun arguments times number > > of stores in the function (much better than number of cfun arguments > > times calls in the function times number of stores in the function). > > Thinking about this again you'd need to manage this caching > yourself somehow (and stop walking in the callback if you hit it). > You can keep a reaches-modification and doesn't-reach-modification > bitmap and OR them from the is_parm_modified_at_call local bitmap > depending on result. > Well, I thought about this and eventually came to the conclusion that trying to do member pointer indirect inlining (and these AA queries are not used for anything else) in presence of complex modifications of the parameters probably isn't worth the complexity. Therefore I decided to use a single visited_stmts bitmap and if is_parm_modified_before_call returns true once, make it return true for that parameter always. This might not bring much more accuracy than we have now but has the benefit of being able to avoid one complete walk of the function. Currently, we need to get the modified flag correct by walking the whole function before we embark on examining call statements looking for indirect calls (including those of member pointers) and calculating jump functions. If we replace the modified flag with AA, this is not necessary and the whole analysis can be done in one walk. Moreover, we currently do two sweeps over all nodes just to get all parameter descriptors and parameter counts initialized and to calculate the modified flag for all nodes before computing the jump functions. If we do the initialization lazily, that is not necessary either. And that is what the patch below does. It still includes a removal of gcc.dg/ipa/modif-1.c because that is just a dump scan for the result of modification analysis which we do not perform with this patch. I did add a new testcase that actually tests we get AA-queries right so the coverage should not get worse. I have bootstrapped and tested a very similar variant on x86-64-linux without any problems, a bootstrap and test of exactly this version is underway. What so you think now? Thanks, Martin 2010-06-24 Martin Jambor * ipa-prop.h (struct ipa_param_descriptor): Removed the modified flag. (struct ipa_node_params): Removed the modification_analysis_done flag. (ipa_is_param_modified): Removed. (ipa_analyze_node): Declare. (ipa_compute_jump_functions): Remove declaration. (ipa_count_arguments): Likewise. (ipa_detect_param_modifications): Likewise. (ipa_analyze_params_uses): Likewise. * ipa-prop.c (struct param_analysis_info): New type. (visit_store_addr_for_mod_analysis): Removed. (visit_load_for_mod_analysis): Renamed to visit_ref_for_mod_analysis, moved down in the file. (ipa_detect_param_modifications): Merged into ipa_analyze_params_uses. (ipa_count_arguments): Made static. (mark_modified): New function. (is_parm_modified_before_call): New function. (compute_pass_through_member_ptrs): New parameter parms_info, call is_parm_modified_before_call instead of ipa_is_param_modified. (ipa_compute_jump_functions_for_edge): New parameter parms_info, pass it to compute_pass_through_member_ptrs. (ipa_compute_jump_functions): New parameter parms_info, pass it to ipa_compute_jump_functions_for_edge. Call ipa_initialize_node_params on the callee if it is analyzed. Made static. (ipa_analyze_indirect_call_uses): New parameter parms_info, call is_parm_modified_before_call instead of ipa_is_param_modified. (ipa_analyze_call_uses): New parameter parms_info, pass it to ipa_analyze_indirect_call_uses. (ipa_analyze_stmt_uses): New parameter parms_info, pass it to ipa_analyze_call_uses. (ipa_analyze_params_uses): New parameter parms_info, pass it to ipa_analyze_stmt_uses. Also perform the used analysis. Made static. (ipa_analyze_node): New function. (ipa_print_node_params): Do not dump the modified flag. (ipa_write_node_info): Assert uses_analysis_done rather than streaming it. Do not stream the modified parameter flag. (ipa_read_node_info): Set uses_analysis_done to 1 instead of streaming it. Do not stream the modified parameter flag. * ipa-cp.c (ipcp_analyze_node): Removed. (ipcp_init_stage): Iterate only once over the nodes, analyze each one with only a call to ipa_analyze_node. * ipa-inline.c (inline_indirect_intraprocedural_analysis): Analyze the node with only a call to ipa_analyze_node. * testsuite/g++.dg/ipa/iinline-3.C: New test. * testsuite/gcc.dg/ipa/modif-1.c: Removed. Index: icln/gcc/ipa-prop.c =================================================================== --- icln.orig/gcc/ipa-prop.c 2010-06-24 12:13:10.000000000 +0200 +++ icln/gcc/ipa-prop.c 2010-06-24 23:13:47.000000000 +0200 @@ -39,6 +39,16 @@ along with GCC; see the file COPYING3. #include "gimple-pretty-print.h" #include "lto-streamer.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 modified; + bitmap visited_statements; +}; + /* Vector where the parameter infos are actually stored. */ VEC (ipa_node_params_t, heap) *ipa_node_params_vector; /* Vector where the parameter infos are actually stored. */ @@ -196,101 +206,10 @@ ipa_initialize_node_params (struct cgrap } } -/* Callback of walk_stmt_load_store_addr_ops for the visit_store and visit_addr - parameters. If OP is a parameter declaration, mark it as modified in the - info structure passed in DATA. */ - -static bool -visit_store_addr_for_mod_analysis (gimple stmt ATTRIBUTE_UNUSED, - tree op, void *data) -{ - struct ipa_node_params *info = (struct ipa_node_params *) data; - - op = get_base_address (op); - if (op - && TREE_CODE (op) == PARM_DECL) - { - int index = ipa_get_param_decl_index (info, op); - gcc_assert (index >= 0); - info->params[index].modified = true; - info->params[index].used = true; - } - - return false; -} - -/* Callback of walk_stmt_load_store_addr_ops for the visit_load. - If OP is a parameter declaration, mark it as used in the info structure - passed in DATA. */ - -static bool -visit_load_for_mod_analysis (gimple stmt ATTRIBUTE_UNUSED, - tree op, void *data) -{ - struct ipa_node_params *info = (struct ipa_node_params *) data; - - op = get_base_address (op); - if (op - && TREE_CODE (op) == PARM_DECL) - { - int index = ipa_get_param_decl_index (info, op); - gcc_assert (index >= 0); - info->params[index].used = true; - } - - return false; -} - -/* Compute which formal parameters of function associated with NODE are locally - modified or their address is taken. Note that this does not apply on - parameters with SSA names but those can and should be analyzed - differently. */ - -void -ipa_detect_param_modifications (struct cgraph_node *node) -{ - 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->modification_analysis_done) - return; - - for (i = 0; i < ipa_get_param_count (info); i++) - { - tree parm = ipa_get_param (info, i); - /* For SSA regs see if parameter is used. For non-SSA we compute - the flag during modification analysis. */ - if (is_gimple_reg (parm) - && gimple_default_def (DECL_STRUCT_FUNCTION (node->decl), parm)) - info->params[i].used = true; - } - - func = DECL_STRUCT_FUNCTION (decl); - FOR_EACH_BB_FN (bb, func) - { - for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi)) - walk_stmt_load_store_addr_ops (gsi_stmt (gsi), info, - visit_load_for_mod_analysis, - visit_store_addr_for_mod_analysis, - visit_store_addr_for_mod_analysis); - for (gsi = gsi_start (phi_nodes (bb)); !gsi_end_p (gsi); gsi_next (&gsi)) - walk_stmt_load_store_addr_ops (gsi_stmt (gsi), info, - visit_load_for_mod_analysis, - visit_store_addr_for_mod_analysis, - visit_store_addr_for_mod_analysis); - } - - info->modification_analysis_done = 1; -} - /* Count number of arguments callsite CS has and store it in ipa_edge_args structure corresponding to this callsite. */ -void +static void ipa_count_arguments (struct cgraph_edge *cs) { gimple stmt; @@ -707,14 +626,53 @@ type_like_member_ptr_p (tree type, tree return true; } +/* Callback of walk_aliased_vdefs. Flags that it has been invoked to the + boolean variable pointed to by DATA. */ + +static bool +mark_modified (ao_ref *ao ATTRIBUTE_UNUSED, tree vdef ATTRIBUTE_UNUSED, + void *data) +{ + bool *b = (bool *) data; + *b = true; + return true; +} + +/* Return true if the formal parameter PARM might have been modified in this + function before reaching the statement CALL. PARM_INFO is a pointer to a + structure containing intermediate information about PARM. */ + +static bool +is_parm_modified_before_call (struct param_analysis_info *parm_info, + gimple call, tree parm) +{ + bool modified = false; + ao_ref refd; + + if (parm_info->modified) + return true; + + ao_ref_init (&refd, parm); + walk_aliased_vdefs (&refd, gimple_vuse (call), mark_modified, + &modified, &parm_info->visited_statements); + if (modified) + { + parm_info->modified = true; + return true; + } + return false; +} + /* Go through arguments of the CALL and for every one that looks like a member pointer, check whether it can be safely declared pass-through and if so, mark that to the corresponding item of jump FUNCTIONS. Return true iff there are non-pass-through member pointers within the arguments. INFO - describes formal parameters of the caller. */ + describes formal parameters of the caller. PARMS_INFO is a pointer to a + vector containing intermediate information about each formal parameter. */ static bool compute_pass_through_member_ptrs (struct ipa_node_params *info, + struct param_analysis_info *parms_info, struct ipa_jump_func *functions, gimple call) { @@ -733,7 +691,7 @@ compute_pass_through_member_ptrs (struct int index = ipa_get_param_decl_index (info, arg); gcc_assert (index >=0); - if (!ipa_is_param_modified (info, index)) + if (!is_parm_modified_before_call (&parms_info[index], call, arg)) { functions[num].type = IPA_JF_PASS_THROUGH; functions[num].value.pass_through.formal_id = index; @@ -887,7 +845,8 @@ compute_cst_member_ptr_arguments (struct to this callsite. */ static void -ipa_compute_jump_functions_for_edge (struct cgraph_edge *cs) +ipa_compute_jump_functions_for_edge (struct param_analysis_info *parms_info, + struct cgraph_edge *cs) { struct ipa_node_params *info = IPA_NODE_REF (cs->caller); struct ipa_edge_args *arguments = IPA_EDGE_REF (cs); @@ -906,7 +865,8 @@ ipa_compute_jump_functions_for_edge (str /* Let's check whether there are any potential member pointers and if so, whether we can determine their functions as pass_through. */ - if (!compute_pass_through_member_ptrs (info, arguments->jump_functions, call)) + if (!compute_pass_through_member_ptrs (info, parms_info, + arguments->jump_functions, call)) return; /* Finally, let's check whether we actually pass a new constant member @@ -917,8 +877,9 @@ ipa_compute_jump_functions_for_edge (str /* Compute jump functions for all edges - both direct and indirect - outgoing from NODE. Also count the actual arguments in the process. */ -void -ipa_compute_jump_functions (struct cgraph_node *node) +static void +ipa_compute_jump_functions (struct cgraph_node *node, + struct param_analysis_info *parms_info) { struct cgraph_edge *cs; @@ -929,16 +890,20 @@ ipa_compute_jump_functions (struct cgrap if (!cs->callee->analyzed && !flag_lto && !flag_whopr) continue; ipa_count_arguments (cs); + /* If the descriptor of the callee is not initialized yet, we have to do + it now. */ + if (cs->callee->analyzed) + ipa_initialize_node_params (cs->callee); if (ipa_get_cs_argument_count (IPA_EDGE_REF (cs)) != ipa_get_param_count (IPA_NODE_REF (cs->callee))) ipa_set_called_with_variable_arg (IPA_NODE_REF (cs->callee)); - ipa_compute_jump_functions_for_edge (cs); + ipa_compute_jump_functions_for_edge (parms_info, cs); } for (cs = node->indirect_calls; cs; cs = cs->next_callee) { ipa_count_arguments (cs); - ipa_compute_jump_functions_for_edge (cs); + ipa_compute_jump_functions_for_edge (parms_info, cs); } } @@ -1022,13 +987,15 @@ ipa_note_param_call (struct cgraph_node } /* Analyze the CALL and examine uses of formal parameters of the caller NODE - (described by INFO). Currently it checks whether the call calls a pointer - that is a formal parameter and if so, the parameter is marked with the - called flag and an indirect call graph edge describing the call is created. - This is very simple for ordinary pointers represented in SSA but not-so-nice - when it comes to member pointers. The ugly part of this function does - nothing more than trying to match the pattern of such a call. An example of - such a pattern is the gimple dump below, the call is on the last line: + (described by INFO). PARMS_INFO is a pointer to a vector containing + intermediate information about each formal parameter. Currently it checks + whether the call calls a pointer that is a formal parameter and if so, the + parameter is marked with the called flag and an indirect call graph edge + describing the call is created. This is very simple for ordinary pointers + represented in SSA but not-so-nice when it comes to member pointers. The + ugly part of this function does nothing more than trying to match the + pattern of such a call. An example of such a pattern is the gimple dump + below, the call is on the last line: : f$__delta_5 = f.__delta; @@ -1074,6 +1041,7 @@ ipa_note_param_call (struct cgraph_node static void ipa_analyze_indirect_call_uses (struct cgraph_node *node, struct ipa_node_params *info, + struct param_analysis_info *parms_info, gimple call, tree target) { gimple def; @@ -1185,7 +1153,8 @@ ipa_analyze_indirect_call_uses (struct c return; index = ipa_get_param_decl_index (info, rec); - if (index >= 0 && !ipa_is_param_modified (info, index)) + if (index >= 0 && !is_parm_modified_before_call (&parms_info[index], + call, rec)) ipa_note_param_call (node, index, call, false); return; @@ -1228,16 +1197,18 @@ ipa_analyze_virtual_call_uses (struct cg } /* Analyze a call statement CALL whether and how it utilizes formal parameters - of the caller (described by INFO). */ + of the caller (described by INFO). PARMS_INFO is a pointer to a vector + containing intermediate information about each formal parameter. */ static void ipa_analyze_call_uses (struct cgraph_node *node, - struct ipa_node_params *info, gimple call) + struct ipa_node_params *info, + struct param_analysis_info *parms_info, gimple call) { tree target = gimple_call_fn (call); if (TREE_CODE (target) == SSA_NAME) - ipa_analyze_indirect_call_uses (node, info, call, target); + ipa_analyze_indirect_call_uses (node, info, parms_info, call, target); else if (TREE_CODE (target) == OBJ_TYPE_REF) ipa_analyze_virtual_call_uses (node, info, call, target); } @@ -1245,45 +1216,116 @@ ipa_analyze_call_uses (struct cgraph_nod /* 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. */ + parameters are called. PARMS_INFO 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, - gimple stmt) + struct param_analysis_info *parms_info, gimple stmt) { if (is_gimple_call (stmt)) - ipa_analyze_call_uses (node, info, stmt); + ipa_analyze_call_uses (node, info, parms_info, stmt); +} + +/* Callback of walk_stmt_load_store_addr_ops for the visit_load. + If OP is a parameter declaration, mark it as used in the info structure + passed in DATA. */ + +static bool +visit_ref_for_mod_analysis (gimple stmt ATTRIBUTE_UNUSED, + tree op, void *data) +{ + struct ipa_node_params *info = (struct ipa_node_params *) data; + + op = get_base_address (op); + if (op + && TREE_CODE (op) == PARM_DECL) + { + int index = ipa_get_param_decl_index (info, op); + gcc_assert (index >= 0); + info->params[index].used = true; + } + + 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. */ + structure, such as parameter flags, notes etc. PARMS_INFO is a pointer to a + vector containing intermediate information about each formal parameter. */ -void -ipa_analyze_params_uses (struct cgraph_node *node) +static void +ipa_analyze_params_uses (struct cgraph_node *node, + struct param_analysis_info *parms_info) { 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; + for (i = 0; i < ipa_get_param_count (info); i++) + { + tree parm = ipa_get_param (info, i); + /* For SSA regs see if parameter is used. For non-SSA we compute + the flag during modification analysis. */ + if (is_gimple_reg (parm) + && gimple_default_def (DECL_STRUCT_FUNCTION (node->decl), parm)) + info->params[i].used = true; + } + 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); - ipa_analyze_stmt_uses (node, info, stmt); + ipa_analyze_stmt_uses (node, info, parms_info, 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 (phi_nodes (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); } info->uses_analysis_done = 1; } +/* Initialize the array describing properties of of formal parameters of NODE, + analyze their uses and and compute jump functions associated witu actual + arguments of calls from within NODE. */ + +void +ipa_analyze_node (struct cgraph_node *node) +{ + struct ipa_node_params *info = IPA_NODE_REF (node); + struct param_analysis_info *parms_info; + int i, param_count; + + ipa_initialize_node_params (node); + + param_count = ipa_get_param_count (info); + parms_info = XALLOCAVEC (struct param_analysis_info, param_count); + memset (parms_info, 0, sizeof (struct param_analysis_info) * param_count); + + ipa_analyze_params_uses (node, parms_info); + ipa_compute_jump_functions (node, parms_info); + + for (i = 0; i < param_count; i++) + if (parms_info[i].visited_statements) + BITMAP_FREE (parms_info[i].visited_statements); +} + + /* Update the jump function DST when the call graph edge correspondng to SRC is is being inlined, knowing that DST is of type ancestor and src of known type. */ @@ -1855,8 +1897,6 @@ ipa_print_node_params (FILE * f, struct (DECL_NAME (temp) ? (*lang_hooks.decl_printable_name) (temp, 2) : "(unnamed)")); - if (ipa_is_param_modified (info, i)) - fprintf (f, " modified"); if (ipa_is_param_used (info, i)) fprintf (f, " used"); fprintf (f, "\n"); @@ -2465,16 +2505,12 @@ ipa_write_node_info (struct output_block bp = bitpack_create (ob->main_stream); bp_pack_value (&bp, info->called_with_var_arguments, 1); - bp_pack_value (&bp, info->uses_analysis_done, 1); - gcc_assert (info->modification_analysis_done + gcc_assert (info->uses_analysis_done || ipa_get_param_count (info) == 0); gcc_assert (!info->node_enqueued); gcc_assert (!info->ipcp_orig_node); for (j = 0; j < ipa_get_param_count (info); j++) - { - bp_pack_value (&bp, info->params[j].modified, 1); - bp_pack_value (&bp, info->params[j].used, 1); - } + bp_pack_value (&bp, info->params[j].used, 1); lto_output_bitpack (&bp); for (e = node->callees; e; e = e->next_callee) { @@ -2504,18 +2540,11 @@ ipa_read_node_info (struct lto_input_blo bp = lto_input_bitpack (ib); info->called_with_var_arguments = bp_unpack_value (&bp, 1); - info->uses_analysis_done = bp_unpack_value (&bp, 1); if (ipa_get_param_count (info) != 0) - { - info->modification_analysis_done = true; - info->uses_analysis_done = true; - } + info->uses_analysis_done = true; info->node_enqueued = false; for (k = 0; k < ipa_get_param_count (info); k++) - { - info->params[k].modified = bp_unpack_value (&bp, 1); - info->params[k].used = bp_unpack_value (&bp, 1); - } + info->params[k].used = bp_unpack_value (&bp, 1); for (e = node->callees; e; e = e->next_callee) { struct ipa_edge_args *args = IPA_EDGE_REF (e); Index: icln/gcc/ipa-prop.h =================================================================== --- icln.orig/gcc/ipa-prop.h 2010-06-24 12:13:10.000000000 +0200 +++ icln/gcc/ipa-prop.h 2010-06-24 12:13:21.000000000 +0200 @@ -161,8 +161,6 @@ struct ipa_param_descriptor struct ipcp_lattice ipcp_lattice; /* PARAM_DECL of this parameter. */ tree decl; - /* Whether the value parameter has been modified within the function. */ - unsigned modified : 1; /* The parameter is used. */ unsigned used : 1; }; @@ -179,8 +177,6 @@ struct ipa_node_params /* Whether this function is called with variable number of actual arguments. */ unsigned called_with_var_arguments : 1; - /* Whether the modification analysis has already been performed. */ - unsigned modification_analysis_done : 1; /* Whether the param uses analysis has already been performed. */ unsigned uses_analysis_done : 1; /* Whether the function is enqueued in an ipa_func_list. */ @@ -228,17 +224,6 @@ ipa_get_param (struct ipa_node_params *i return info->params[i].decl; } -/* Return the modification flag corresponding to the Ith formal parameter of - the function associated with INFO. Note that there is no setter method as - the goal is to set all flags when building the array in - ipa_detect_param_modifications. */ - -static inline bool -ipa_is_param_modified (struct ipa_node_params *info, int i) -{ - return info->params[i].modified; -} - /* Return the used flag corresponding to the Ith formal parameter of the function associated with INFO. */ @@ -412,14 +397,10 @@ ipa_push_func_to_list (struct ipa_func_l ipa_push_func_to_list_1 (wl, node, info); } -/* Callsite related calculations. */ -void ipa_compute_jump_functions (struct cgraph_node *); -void ipa_count_arguments (struct cgraph_edge *); +void ipa_analyze_node (struct cgraph_node *); /* Function formal parameters related computations. */ void ipa_initialize_node_params (struct cgraph_node *node); -void ipa_detect_param_modifications (struct cgraph_node *); -void ipa_analyze_params_uses (struct cgraph_node *); bool ipa_propagate_indirect_call_infos (struct cgraph_edge *cs, VEC (cgraph_edge_p, heap) **new_edges); Index: icln/gcc/testsuite/g++.dg/ipa/iinline-3.C =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ icln/gcc/testsuite/g++.dg/ipa/iinline-3.C 2010-06-24 12:13:21.000000000 +0200 @@ -0,0 +1,64 @@ +/* Verify that we do not indirect-inline using member pointer + parameters which have been modified. */ +/* { dg-do run } */ +/* { dg-options "-O3 -fno-early-inlining" } */ +/* { dg-add-options bind_pic_locally } */ + +extern "C" void abort (void); + +class String +{ +private: + const char *data; + +public: + String (const char *d) : data(d) + {} + + int funcOne (int stuff) const; + int funcTwo (int stuff) const; +}; + + +int String::funcOne (int stuff) const +{ + return stuff + 1; +} + +int String::funcTwo (int stuff) const +{ + return stuff + 100; +} + +int (String::* gmp)(int stuff) const = &String::funcTwo; + +int docalling_1 (int (String::* f)(int stuff) const) +{ + String S ("muhehehe"); + + return (S.*f)(4); +} + +int docalling (int a, int (String::* f)(int stuff) const) +{ + if (a < 200) + f = gmp; + + return docalling_1 (f); +} + +int __attribute__ ((noinline,noclone)) get_input (void) +{ + return 1; +} + +int main (int argc, char *argv[]) +{ + int i = 0; + while (i < 10) + i += docalling (get_input (), &String::funcOne); + + if (i != 104) + abort(); + return 0; +} Index: icln/gcc/ipa-cp.c =================================================================== --- icln.orig/gcc/ipa-cp.c 2010-06-24 12:13:10.000000000 +0200 +++ icln/gcc/ipa-cp.c 2010-06-24 23:43:34.000000000 +0200 @@ -177,18 +177,6 @@ ipcp_init_cloned_node (struct cgraph_nod IPA_NODE_REF (new_node)->ipcp_orig_node = orig_node; } -/* Perform intraprocedrual analysis needed for ipcp. */ -static void -ipcp_analyze_node (struct cgraph_node *node) -{ - /* Unreachable nodes should have been eliminated before ipcp. */ - gcc_assert (node->needed || node->reachable); - - node->local.versionable = tree_versionable_function_p (node->decl); - ipa_initialize_node_params (node); - ipa_detect_param_modifications (node); -} - /* Return scale for NODE. */ static inline gcov_type ipcp_get_node_scale (struct cgraph_node *node) @@ -611,6 +599,7 @@ ipcp_compute_node_scale (struct cgraph_n /* Initialization and computation of IPCP data structures. This is the initial intraprocedural analysis of functions, which gathers information to be propagated later on. */ + static void ipcp_init_stage (void) { @@ -618,16 +607,13 @@ ipcp_init_stage (void) for (node = cgraph_nodes; node; node = node->next) if (node->analyzed) - ipcp_analyze_node (node); - for (node = cgraph_nodes; node; node = node->next) - { - if (!node->analyzed) - continue; - - ipa_analyze_params_uses (node); - /* building jump functions */ - ipa_compute_jump_functions (node); - } + { + /* Unreachable nodes should have been eliminated before ipcp. */ + gcc_assert (node->needed || node->reachable); + + node->local.versionable = tree_versionable_function_p (node->decl); + ipa_analyze_node (node); + } } /* Return true if there are some formal parameters whose value is IPA_TOP (in Index: icln/gcc/ipa-inline.c =================================================================== --- icln.orig/gcc/ipa-inline.c 2010-06-24 12:13:10.000000000 +0200 +++ icln/gcc/ipa-inline.c 2010-06-24 23:52:44.000000000 +0200 @@ -2011,12 +2011,8 @@ struct gimple_opt_pass pass_inline_param static void inline_indirect_intraprocedural_analysis (struct cgraph_node *node) { - ipa_initialize_node_params (node); - ipa_detect_param_modifications (node); - ipa_analyze_params_uses (node); - ipa_compute_jump_functions (node); - - if (dump_file) + ipa_analyze_node (node); + if (dump_file && (dump_flags & TDF_DETAILS)) { ipa_print_node_params (dump_file, node); ipa_print_node_jump_functions (dump_file, node);