From fdb0e1b4bcf88b63bb6bc0b6a6d52b32a1016f7d Mon Sep 17 00:00:00 2001 From: Martin Jambor Date: Mon, 31 Oct 2011 18:43:25 +0100 Subject: [PATCH] ipa-prop.c (mark_modified): Moved up in the file. 2011-10-31 Martin Jambor * ipa-prop.c (mark_modified): Moved up in the file. (is_parm_modified_before_call): Renamed to is_parm_modified_before_stmt, moved up in the file. (load_from_unmodified_param): New function. (compute_complex_assign_jump_func): Also attempt to create pass through jump functions for values loaded from (addressable) parameters. * testsuite/gcc.dg/ipa/ipcp-4.c: New test. From-SVN: r180705 --- gcc/ChangeLog | 10 ++ gcc/ipa-prop.c | 203 +++++++++++++++++++++--------- gcc/testsuite/ChangeLog | 4 + gcc/testsuite/gcc.dg/ipa/ipcp-4.c | 68 ++++++++++ 4 files changed, 228 insertions(+), 57 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/ipa/ipcp-4.c diff --git a/gcc/ChangeLog b/gcc/ChangeLog index ada5acbd16e..28112f7acb6 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,13 @@ +2011-10-31 Martin Jambor + + * ipa-prop.c (mark_modified): Moved up in the file. + (is_parm_modified_before_call): Renamed to + is_parm_modified_before_stmt, moved up in the file. + (load_from_unmodified_param): New function. + (compute_complex_assign_jump_func): Also attempt to create pass + through jump functions for values loaded from (addressable) + parameters. + 2011-10-31 Jakub Jelinek * tree-vect-stmts.c (vectorizable_shift): If op1 is vect_external_def diff --git a/gcc/ipa-prop.c b/gcc/ipa-prop.c index f4778124272..e624426d698 100644 --- a/gcc/ipa-prop.c +++ b/gcc/ipa-prop.c @@ -419,31 +419,154 @@ detect_type_change_ssa (tree arg, gimple call, struct ipa_jump_func *jfunc) return detect_type_change (arg, arg, call, jfunc, 0); } +/* 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 STMT. PARM_AINFO is a pointer to a + structure containing temporary information about PARM. */ + +static bool +is_parm_modified_before_stmt (struct param_analysis_info *parm_ainfo, + gimple stmt, tree parm) +{ + bool modified = false; + ao_ref refd; + + if (parm_ainfo->modified) + return true; + + gcc_checking_assert (gimple_vuse (stmt) != NULL_TREE); + ao_ref_init (&refd, parm); + walk_aliased_vdefs (&refd, gimple_vuse (stmt), mark_modified, + &modified, &parm_ainfo->visited_statements); + if (modified) + { + parm_ainfo->modified = true; + return true; + } + return false; +} + +/* If STMT is an assignment that loads a value from an parameter declaration, + return the index of the parameter in ipa_node_params which has not been + modified. Otherwise return -1. */ + +static int +load_from_unmodified_param (struct ipa_node_params *info, + struct param_analysis_info *parms_ainfo, + gimple stmt) +{ + int index; + tree op1; + + if (!gimple_assign_single_p (stmt)) + return -1; + + op1 = gimple_assign_rhs1 (stmt); + if (TREE_CODE (op1) != PARM_DECL) + return -1; + + index = ipa_get_param_decl_index (info, op1); + if (index < 0 + || is_parm_modified_before_stmt (&parms_ainfo[index], stmt, op1)) + return -1; + + return index; +} /* Given that an actual argument is an SSA_NAME (given in NAME) and is a result - of an assignment statement STMT, try to find out whether NAME can be - described by a (possibly polynomial) pass-through jump-function or an - ancestor jump function and if so, write the appropriate function into - JFUNC */ + of an assignment statement STMT, try to determine whether we are actually + handling any of the following cases and construct an appropriate jump + function into JFUNC if so: + + 1) The passed value is loaded from a formal parameter which is not a gimple + register (most probably because it is addressable, the value has to be + scalar) and we can guarantee the value has not changed. This case can + therefore be described by a simple pass-through jump function. For example: + + foo (int a) + { + int a.0; + + a.0_2 = a; + bar (a.0_2); + + 2) The passed value can be described by a simple arithmetic pass-through + jump function. E.g. + + foo (int a) + { + int D.2064; + + D.2064_4 = a.1(D) + 4; + bar (D.2064_4); + + This case can also occur in combination of the previous one, e.g.: + + foo (int a, int z) + { + int a.0; + int D.2064; + + a.0_3 = a; + D.2064_4 = a.0_3 + 4; + foo (D.2064_4); + + 3) The passed value is an address of an object within another one (which + also passed by reference). Such situations are described by an ancestor + jump function and describe situations such as: + + B::foo() (struct B * const this) + { + struct A * D.1845; + + D.1845_2 = &this_1(D)->D.1748; + A::bar (D.1845_2); + + INFO is the structure describing individual parameters access different + stages of IPA optimizations. PARMS_AINFO contains the information that is + 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) { HOST_WIDE_INT offset, size, max_size; - tree op1, op2, base, ssa; + tree op1, tc_ssa, base, ssa; int index; op1 = gimple_assign_rhs1 (stmt); - op2 = gimple_assign_rhs2 (stmt); - if (TREE_CODE (op1) == SSA_NAME - && SSA_NAME_IS_DEFAULT_DEF (op1)) + if (TREE_CODE (op1) == SSA_NAME) { - index = ipa_get_param_decl_index (info, SSA_NAME_VAR (op1)); - if (index < 0) - return; + 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, parms_ainfo, + SSA_NAME_DEF_STMT (op1)); + tc_ssa = op1; + } + else + { + index = load_from_unmodified_param (info, parms_ainfo, stmt); + tc_ssa = gimple_assign_lhs (stmt); + } + + if (index >= 0) + { + tree op2 = gimple_assign_rhs2 (stmt); if (op2) { @@ -458,8 +581,8 @@ compute_complex_assign_jump_func (struct ipa_node_params *info, jfunc->value.pass_through.operation = gimple_assign_rhs_code (stmt); jfunc->value.pass_through.operand = op2; } - else if (gimple_assign_unary_nop_p (stmt) - && !detect_type_change_ssa (op1, call, jfunc)) + else if (gimple_assign_single_p (stmt) + && !detect_type_change_ssa (tc_ssa, call, jfunc)) { jfunc->type = IPA_JF_PASS_THROUGH; jfunc->value.pass_through.formal_id = index; @@ -665,12 +788,14 @@ compute_known_type_jump_func (tree op, struct ipa_jump_func *jfunc, /* Determine the jump functions of scalar arguments. Scalar means SSA names and constants of a number of selected types. INFO is the ipa_node_params - structure associated with the caller, FUNCTIONS is a pointer to an array of - jump function structures associated with CALL which is the call statement - being examined.*/ + structure associated with the caller, PARMS_AINFO describes state of + analysis with respect to individual formal parameters. ARGS is the + ipa_edge_args structure describing the callsite CALL which is the call + statement being examined.*/ static void compute_scalar_jump_functions (struct ipa_node_params *info, + struct param_analysis_info *parms_ainfo, struct ipa_edge_args *args, gimple call) { @@ -705,7 +830,8 @@ compute_scalar_jump_functions (struct ipa_node_params *info, { gimple stmt = SSA_NAME_DEF_STMT (arg); if (is_gimple_assign (stmt)) - compute_complex_assign_jump_func (info, jfunc, call, stmt, arg); + compute_complex_assign_jump_func (info, parms_ainfo, jfunc, + call, stmt, arg); else if (gimple_code (stmt) == GIMPLE_PHI) compute_complex_ancestor_jump_func (info, jfunc, call, stmt); } @@ -748,43 +874,6 @@ 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 @@ -813,7 +902,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 (!is_parm_modified_before_call (&parms_ainfo[index], call, + if (!is_parm_modified_before_stmt (&parms_ainfo[index], call, arg)) { struct ipa_jump_func *jfunc = ipa_get_ith_jump_func (args, @@ -982,7 +1071,7 @@ ipa_compute_jump_functions_for_edge (struct param_analysis_info *parms_ainfo, VEC_safe_grow_cleared (ipa_jump_func_t, gc, args->jump_functions, arg_num); /* We will deal with constants and SSA scalars first: */ - compute_scalar_jump_functions (info, args, call); + compute_scalar_jump_functions (info, parms_ainfo, args, call); /* Let's check whether there are any potential member pointers and if so, whether we can determine their functions as pass_through. */ @@ -1284,7 +1373,7 @@ ipa_analyze_indirect_call_uses (struct cgraph_node *node, return; index = ipa_get_param_decl_index (info, rec); - if (index >= 0 && !is_parm_modified_before_call (&parms_ainfo[index], + if (index >= 0 && !is_parm_modified_before_stmt (&parms_ainfo[index], call, rec)) ipa_note_param_call (node, index, call); diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index f58934b472a..244a665487d 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,7 @@ +2011-10-31 Martin Jambor + + * gcc.dg/ipa/ipcp-4.c: New test. + 2011-10-31 Jakub Jelinek * gcc.dg/vshift-3.c: New test. diff --git a/gcc/testsuite/gcc.dg/ipa/ipcp-4.c b/gcc/testsuite/gcc.dg/ipa/ipcp-4.c new file mode 100644 index 00000000000..59018ca6b1e --- /dev/null +++ b/gcc/testsuite/gcc.dg/ipa/ipcp-4.c @@ -0,0 +1,68 @@ +/* Test that IPA-CP is able to produce a pass-through jump function for the + call of g1 and g2 even though a is addressable. Also test that h is not + cloned. */ + +/* { dg-do compile } */ +/* { dg-options "-O3 -fipa-cp -fipa-cp-clone -fdump-ipa-cp -fno-early-inlining" } */ +/* { dg-add-options bind_pic_locally } */ + +extern void use_stuff (int); +extern void use_pointer (int *); + +static int +h (int a, int b) +{ + int i; + + for (i = 8; i <= b; i++) + use_stuff (a+8); +} + +static int +g1 (int a, int b) +{ + int i; + + for (i = 0; i <= b; i++) + use_pointer (&a); + h (a, b); +} + +static int +g2 (int a, int b) +{ + int i; + + for (i = 4; i <= b; i += 2) + use_stuff (a); +} + + +static void +f (int a, int z) +{ + if (z > 1) + g1 (a, z); + else + g2 (a + 4, z); + use_pointer (&a); +} + +int +main (int argc, char *argv[]) +{ + int i; + for (i = 0; i < 100; i++) + f (7, argc); + return 0; +} + + +/* { dg-final { scan-ipa-dump "Creating a specialized node of g1.*for all known contexts" "cp" } } */ +/* { dg-final { scan-ipa-dump "Creating a specialized node of g2.*for all known contexts" "cp" } } */ +/* { dg-final { scan-ipa-dump-not "Creating a specialized node of h.*for all known contexts" "cp" } } */ +/* { dg-final { scan-ipa-dump-times "replacing param a with const 7" 2 "cp" } } */ +/* { dg-final { scan-ipa-dump "replacing param a with const 11" "cp" } } */ +/* { dg-final { cleanup-ipa-dump "cp" } } */ + +