ipa-prop.h (struct ipa_param_descriptor): Removed the modified flag.
2010-06-25 Martin Jambor <mjambor@suse.cz> * 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. From-SVN: r161384
This commit is contained in:
parent
212580ffb8
commit
062c604fc5
@ -1,3 +1,48 @@
|
||||
2010-06-25 Martin Jambor <mjambor@suse.cz>
|
||||
|
||||
* 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.
|
||||
|
||||
2010-06-25 Manuel López-Ibáñez <manu@gcc.gnu.org>
|
||||
|
||||
* doc/invoke.texi (-Wsuggest-attribute): Add item for noreturn.
|
||||
|
28
gcc/ipa-cp.c
28
gcc/ipa-cp.c
@ -177,18 +177,6 @@ ipcp_init_cloned_node (struct cgraph_node *orig_node,
|
||||
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_node *node)
|
||||
/* 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;
|
||||
{
|
||||
/* Unreachable nodes should have been eliminated before ipcp. */
|
||||
gcc_assert (node->needed || node->reachable);
|
||||
|
||||
ipa_analyze_params_uses (node);
|
||||
/* building jump functions */
|
||||
ipa_compute_jump_functions (node);
|
||||
}
|
||||
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
|
||||
|
@ -2011,12 +2011,8 @@ struct gimple_opt_pass pass_inline_parameters =
|
||||
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);
|
||||
|
303
gcc/ipa-prop.c
303
gcc/ipa-prop.c
@ -39,6 +39,16 @@ along with GCC; see the file COPYING3. If not see
|
||||
#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 cgraph_node *node)
|
||||
}
|
||||
}
|
||||
|
||||
/* 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 *method_ptr, tree *delta)
|
||||
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 ipa_node_params *info,
|
||||
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;
|
||||
@ -886,7 +844,8 @@ compute_cst_member_ptr_arguments (struct ipa_jump_func *functions,
|
||||
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);
|
||||
@ -905,7 +864,8 @@ ipa_compute_jump_functions_for_edge (struct cgraph_edge *cs)
|
||||
|
||||
/* 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
|
||||
@ -916,8 +876,9 @@ ipa_compute_jump_functions_for_edge (struct cgraph_edge *cs)
|
||||
/* 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;
|
||||
|
||||
@ -928,16 +889,20 @@ ipa_compute_jump_functions (struct cgraph_node *node)
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1021,13 +986,15 @@ ipa_note_param_call (struct cgraph_node *node, int param_index, gimple stmt,
|
||||
}
|
||||
|
||||
/* 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:
|
||||
|
||||
<bb 2>:
|
||||
f$__delta_5 = f.__delta;
|
||||
@ -1073,6 +1040,7 @@ ipa_note_param_call (struct cgraph_node *node, int param_index, gimple stmt,
|
||||
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;
|
||||
@ -1184,7 +1152,8 @@ ipa_analyze_indirect_call_uses (struct cgraph_node *node,
|
||||
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;
|
||||
@ -1227,16 +1196,18 @@ ipa_analyze_virtual_call_uses (struct cgraph_node *node,
|
||||
}
|
||||
|
||||
/* 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);
|
||||
}
|
||||
@ -1244,45 +1215,120 @@ ipa_analyze_call_uses (struct cgraph_node *node,
|
||||
|
||||
/* 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);
|
||||
|
||||
if (is_gimple_debug (stmt))
|
||||
continue;
|
||||
|
||||
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. */
|
||||
@ -1854,8 +1900,6 @@ ipa_print_node_params (FILE * f, struct cgraph_node *node)
|
||||
(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");
|
||||
@ -2464,16 +2508,12 @@ ipa_write_node_info (struct output_block *ob, struct cgraph_node *node)
|
||||
|
||||
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)
|
||||
{
|
||||
@ -2503,18 +2543,11 @@ ipa_read_node_info (struct lto_input_block *ib, struct cgraph_node *node,
|
||||
|
||||
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);
|
||||
|
@ -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 *info, int 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_list **wl, struct cgraph_node *node)
|
||||
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);
|
||||
|
||||
|
@ -1,3 +1,8 @@
|
||||
2010-06-25 Martin Jambor <mjambor@suse.cz>
|
||||
|
||||
* g++.dg/ipa/iinline-3.C: New test.
|
||||
* gcc.dg/ipa/modif-1.c: Removed.
|
||||
|
||||
2010-06-25 Jan Hubicka <jh@suse.cz>
|
||||
|
||||
* testsuite/gcc.dg/tree-ssa/ipa-split-1.c
|
||||
|
64
gcc/testsuite/g++.dg/ipa/iinline-3.C
Normal file
64
gcc/testsuite/g++.dg/ipa/iinline-3.C
Normal file
@ -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;
|
||||
}
|
@ -1,41 +0,0 @@
|
||||
/* Verify that modification analysis detects modfications. */
|
||||
/* { dg-do compile } */
|
||||
/* { dg-options "-O3 -c -fdump-ipa-inline-details -fno-early-inlining" } */
|
||||
|
||||
struct whatever
|
||||
{
|
||||
int first;
|
||||
unsigned second;
|
||||
};
|
||||
|
||||
void func1 (struct whatever w);
|
||||
void func2 (struct whatever *pw);
|
||||
void func3 (int i);
|
||||
void func4 (int *pi);
|
||||
|
||||
void the_test (struct whatever u, struct whatever v,
|
||||
struct whatever w, struct whatever x,
|
||||
int i, int k, int l)
|
||||
{
|
||||
struct whatever *pw = &w;
|
||||
int *pk = &k;
|
||||
|
||||
v.first = 9;
|
||||
|
||||
func1 (u);
|
||||
func1 (v);
|
||||
func2 (pw);
|
||||
func2 (&x);
|
||||
func3 (i);
|
||||
func4 (pk);
|
||||
func4 (&l);
|
||||
}
|
||||
|
||||
/* { dg-final { scan-ipa-dump-not "param 0\[^\\n\]*modified" "inline" } } */
|
||||
/* { dg-final { scan-ipa-dump "param 1\[^\\n\]*modified" "inline" } } */
|
||||
/* { dg-final { scan-ipa-dump "param 2\[^\\n\]*modified" "inline" } } */
|
||||
/* { dg-final { scan-ipa-dump "param 3\[^\\n\]*modified" "inline" } } */
|
||||
/* { dg-final { scan-ipa-dump-not "param 4\[^\\n\]*modified" "inline" } } */
|
||||
/* { dg-final { scan-ipa-dump "param 5\[^\\n\]*modified" "inline" } } */
|
||||
/* { dg-final { scan-ipa-dump "param 6\[^\\n\]*modified" "inline" } } */
|
||||
/* { dg-final { cleanup-ipa-dump "inline" } } */
|
Loading…
Reference in New Issue
Block a user