diff options
author | Martin Jambor <mjambor@suse.cz> | 2010-08-05 15:23:07 +0200 |
---|---|---|
committer | Martin Jambor <jamborm@gcc.gnu.org> | 2010-08-05 15:23:07 +0200 |
commit | 3949c4a710360edb924d4c88a8974ed0bbfa9f20 (patch) | |
tree | d7635a83c603a76ecd0568209e0c2e2385f551c2 /gcc/ipa-cp.c | |
parent | 4caa21a13b14b333714d1f8dcce3adefe6fe910e (diff) | |
download | gcc-3949c4a710360edb924d4c88a8974ed0bbfa9f20.zip gcc-3949c4a710360edb924d4c88a8974ed0bbfa9f20.tar.gz gcc-3949c4a710360edb924d4c88a8974ed0bbfa9f20.tar.bz2 |
ipa-prop.h (enum ipa_lattice_type): Changed comments.
2010-08-05 Martin Jambor <mjambor@suse.cz>
* ipa-prop.h (enum ipa_lattice_type): Changed comments.
(struct ipa_param_descriptor): New fields types and
cannot_devirtualize.
(ipa_param_cannot_devirtualize_p): New function.
(ipa_param_types_vec_empty): Likewise.
(ipa_make_edge_direct_to_target): Declare.
* ipa-cp.c: Fixed first stage driver name in initial comment,
described devirtualization there too.
(ipcp_analyze_node): Call ipa_analyze_params_uses.
(ipcp_print_all_lattices): Print devirtualization info.
(ipa_set_param_cannot_devirtualize): New function.
(ipcp_initialize_node_lattices): Set cannot_devirtualize when setting
lattice to BOTTOM.
(ipcp_init_stage): Merged into...
(ipcp_generate_summary): ...its caller.
(ipcp_change_tops_to_bottom): Also process type lists.
(ipcp_add_param_type): New function.
(ipcp_copy_types): Likewise.
(ipcp_propagate_types): Likewise.
(ipcp_propagate_stage): Also propagate types.
(ipcp_need_redirect_p): Variable jump_func moved to its scope block.
Also return true if propagated types require it.
(ipcp_update_callgraph): Dump redirection info.
(ipcp_process_devirtualization_opportunities): New function.
(ipcp_const_param_count): Include known type information.
(ipcp_insert_stage): Call ipcp_process_devirtualization_opportunities
on new node. Fixed formatting.
* ipa-prop.c (make_edge_direct_to_target): Renamed to
ipa_make_edge_direct_to_target and changed all callers. Made
externally visible.
(ipa_node_duplication_hook): Duplicate types vector.
* cgraphunit.c (cgraph_redirect_edge_call_stmt_to_callee): Also try to
redirect outgoing calls for which we can't get a decl from the
statement. Check that we can get a decl from the call statement.
* ipa-inline.c (inline_indirect_intraprocedural_analysis): Call
ipa_analyze_params_uses only when ipa-cp is disabled.
* tree-inline.c (get_indirect_callee_fndecl): Removed.
(expand_call_inline): Do not call get_indirect_callee_fndecl.
* params.def (PARAM_DEVIRT_TYPE_LIST_SIZE): New parameter.
* Makefile.in (ipa-cp.o): Add gimple.h to dependencies.
* testsuite/g++.dg/ipa/devirt-1.C: New test.
* testsuite/g++.dg/ipa/devirt-2.C: Likewise.
* testsuite/g++.dg/ipa/devirt-3.C: Likewise.
* testsuite/g++.dg/ipa/devirt-4.C: Likewise.
* testsuite/g++.dg/ipa/devirt-5.C: Likewise.
* testsuite/gcc.dg/ipa/iinline-3.c: Likewise.
From-SVN: r162911
Diffstat (limited to 'gcc/ipa-cp.c')
-rw-r--r-- | gcc/ipa-cp.c | 316 |
1 files changed, 275 insertions, 41 deletions
diff --git a/gcc/ipa-cp.c b/gcc/ipa-cp.c index 6918273..354a404 100644 --- a/gcc/ipa-cp.c +++ b/gcc/ipa-cp.c @@ -70,7 +70,7 @@ along with GCC; see the file COPYING3. If not see modified_flags are defined in ipa_node_params structure (defined in ipa_prop.h and pointed to by cgraph_edge->aux). - -ipcp_init_stage() is the first stage driver. + -ipcp_generate_summary() is the first stage driver. Second stage - interprocedural analysis ======================================== @@ -117,6 +117,17 @@ along with GCC; see the file COPYING3. If not see -ipcp_insert_stage() is the third phase driver. + + This pass also performs devirtualization - turns virtual calls into direct + ones if it can prove that all invocations of the function call the same + callee. This is achieved by building a list of all base types (actually, + their BINFOs) that individual parameters can have in an iterative matter + just like propagating scalar constants and then examining whether virtual + calls which take a parameter as their object fold to the same target for all + these types. If we cannot enumerate all types or there is a type which does + not have any BINFO associated with it, cannot_devirtualize of the associated + parameter descriptor is set which is an equivalent of BOTTOM lattice value + in standard IPA constant propagation. */ #include "config.h" @@ -124,6 +135,7 @@ along with GCC; see the file COPYING3. If not see #include "coretypes.h" #include "tree.h" #include "target.h" +#include "gimple.h" #include "cgraph.h" #include "ipa-prop.h" #include "tree-flow.h" @@ -393,12 +405,17 @@ ipcp_print_all_lattices (FILE * f) print_generic_expr (f, DECL_INITIAL (TREE_OPERAND (cst, 0)), 0); } - fprintf (f, "\n"); } else if (lat->type == IPA_TOP) - fprintf (f, "type is TOP\n"); + fprintf (f, "type is TOP"); + else + fprintf (f, "type is BOTTOM"); + if (ipa_param_cannot_devirtualize_p (info, i)) + fprintf (f, " - cannot_devirtualize set\n"); + else if (ipa_param_types_vec_empty (info, i)) + fprintf (f, " - type list empty\n"); else - fprintf (f, "type is BOTTOM\n"); + fprintf (f, "\n"); } } } @@ -523,6 +540,19 @@ ipcp_cloning_candidate_p (struct cgraph_node *node) return true; } +/* Mark parameter with index I of function described by INFO as unsuitable for + devirtualization. Return true if it has already been marked so. */ + +static bool +ipa_set_param_cannot_devirtualize (struct ipa_node_params *info, int i) +{ + bool ret = info->params[i].cannot_devirtualize; + info->params[i].cannot_devirtualize = true; + if (info->params[i].types) + VEC_free (tree, heap, info->params[i].types); + return ret; +} + /* Initialize ipcp_lattices array. The lattices corresponding to supported types (integers, real types and Fortran constants defined as const_decls) are initialized to IPA_TOP, the rest of them to IPA_BOTTOM. */ @@ -545,7 +575,11 @@ ipcp_initialize_node_lattices (struct cgraph_node *node) type = IPA_BOTTOM; for (i = 0; i < ipa_get_param_count (info) ; i++) - ipcp_get_lattice (info, i)->type = type; + { + ipcp_get_lattice (info, i)->type = type; + if (type == IPA_BOTTOM) + ipa_set_param_cannot_devirtualize (info, i); + } } /* build INTEGER_CST tree with type TREE_TYPE and value according to LAT. @@ -599,26 +633,6 @@ ipcp_compute_node_scale (struct cgraph_node *node) ipcp_set_node_scale (node, sum * REG_BR_PROB_BASE / node->count); } -/* 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) -{ - struct cgraph_node *node; - - for (node = cgraph_nodes; node; node = node->next) - if (node->analyzed) - { - /* 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 the whole compilation unit). Change their values to IPA_BOTTOM, since they most probably get their values from outside of this compilation unit. */ @@ -649,11 +663,148 @@ ipcp_change_tops_to_bottom (void) } lat->type = IPA_BOTTOM; } + if (!ipa_param_cannot_devirtualize_p (info, i) + && ipa_param_types_vec_empty (info, i)) + { + prop_again = true; + ipa_set_param_cannot_devirtualize (info, i); + if (dump_file) + { + fprintf (dump_file, "Marking param "); + print_generic_expr (dump_file, ipa_get_param (info, i), 0); + fprintf (dump_file, " of node %s as unusable for " + "devirtualization.\n", + cgraph_node_name (node)); + } + } } } return prop_again; } +/* Insert BINFO to the list of known types of parameter number I of the + function described by CALLEE_INFO. Return true iff the type information + associated with the callee parameter changed in any way. */ + +static bool +ipcp_add_param_type (struct ipa_node_params *callee_info, int i, tree binfo) +{ + int j, count; + + if (ipa_param_cannot_devirtualize_p (callee_info, i)) + return false; + + if (callee_info->params[i].types) + { + count = VEC_length (tree, callee_info->params[i].types); + for (j = 0; j < count; j++) + if (VEC_index (tree, callee_info->params[i].types, j) == binfo) + return false; + } + + if (VEC_length (tree, callee_info->params[i].types) + == (unsigned) PARAM_VALUE (PARAM_DEVIRT_TYPE_LIST_SIZE)) + return !ipa_set_param_cannot_devirtualize (callee_info, i); + + VEC_safe_push (tree, heap, callee_info->params[i].types, binfo); + return true; +} + +/* Copy known types information for parameter number CALLEE_IDX of CALLEE_INFO + from a parameter of CALLER_INFO as described by JF. Return true iff the + type information changed in any way. JF must be a pass-through or an + ancestor jump function. */ + +static bool +ipcp_copy_types (struct ipa_node_params *caller_info, + struct ipa_node_params *callee_info, + int callee_idx, struct ipa_jump_func *jf) +{ + int caller_idx, j, count; + bool res; + + if (ipa_param_cannot_devirtualize_p (callee_info, callee_idx)) + return false; + + if (jf->type == IPA_JF_PASS_THROUGH) + { + if (jf->value.pass_through.operation != NOP_EXPR) + { + ipa_set_param_cannot_devirtualize (callee_info, callee_idx); + return true; + } + caller_idx = jf->value.pass_through.formal_id; + } + else + caller_idx = jf->value.ancestor.formal_id; + + if (ipa_param_cannot_devirtualize_p (caller_info, caller_idx)) + { + ipa_set_param_cannot_devirtualize (callee_info, callee_idx); + return true; + } + + if (!caller_info->params[caller_idx].types) + return false; + + res = false; + count = VEC_length (tree, caller_info->params[caller_idx].types); + for (j = 0; j < count; j++) + { + tree binfo = VEC_index (tree, caller_info->params[caller_idx].types, j); + if (jf->type == IPA_JF_ANCESTOR) + { + binfo = get_binfo_at_offset (binfo, jf->value.ancestor.offset, + jf->value.ancestor.type); + if (!binfo) + { + ipa_set_param_cannot_devirtualize (callee_info, callee_idx); + return true; + } + } + res |= ipcp_add_param_type (callee_info, callee_idx, binfo); + } + return res; +} + +/* Propagate type information for parameter of CALLEE_INFO number I as + described by JF. CALLER_INFO describes the caller. Return true iff the + type information changed in any way. */ + +static bool +ipcp_propagate_types (struct ipa_node_params *caller_info, + struct ipa_node_params *callee_info, + struct ipa_jump_func *jf, int i) +{ + tree cst, binfo; + + switch (jf->type) + { + case IPA_JF_UNKNOWN: + case IPA_JF_CONST_MEMBER_PTR: + break; + + case IPA_JF_KNOWN_TYPE: + return ipcp_add_param_type (callee_info, i, jf->value.base_binfo); + + case IPA_JF_CONST: + cst = jf->value.constant; + if (TREE_CODE (cst) != ADDR_EXPR) + break; + binfo = gimple_get_relevant_ref_binfo (TREE_OPERAND (cst, 0), NULL_TREE); + if (!binfo) + break; + return ipcp_add_param_type (callee_info, i, binfo); + + case IPA_JF_PASS_THROUGH: + case IPA_JF_ANCESTOR: + return ipcp_copy_types (caller_info, callee_info, i, jf); + } + + /* If we reach this we cannot use this parameter for devirtualization. */ + return !ipa_set_param_cannot_devirtualize (callee_info, i); +} + /* Interprocedural analysis. The algorithm propagates constants from the caller's parameters to the callee's arguments. */ static void @@ -701,6 +852,9 @@ ipcp_propagate_stage (void) dest_lat->constant = new_lat.constant; ipa_push_func_to_list (&wl, cs->callee); } + + if (ipcp_propagate_types (info, callee_info, jump_func, i)) + ipa_push_func_to_list (&wl, cs->callee); } } } @@ -852,7 +1006,6 @@ ipcp_need_redirect_p (struct cgraph_edge *cs) { struct ipa_node_params *orig_callee_info; int i, count; - struct ipa_jump_func *jump_func; struct cgraph_node *node = cs->callee, *orig; if (!n_cloning_candidates) @@ -868,12 +1021,16 @@ ipcp_need_redirect_p (struct cgraph_edge *cs) for (i = 0; i < count; i++) { struct ipcp_lattice *lat = ipcp_get_lattice (orig_callee_info, i); - if (ipcp_lat_is_const (lat)) - { - jump_func = ipa_get_ith_jump_func (IPA_EDGE_REF (cs), i); - if (jump_func->type != IPA_JF_CONST) - return true; - } + struct ipa_jump_func *jump_func; + + jump_func = ipa_get_ith_jump_func (IPA_EDGE_REF (cs), i); + if ((ipcp_lat_is_const (lat) + && jump_func->type != IPA_JF_CONST) + || (!ipa_param_cannot_devirtualize_p (orig_callee_info, i) + && !ipa_param_types_vec_empty (orig_callee_info, i) + && jump_func->type != IPA_JF_CONST + && jump_func->type != IPA_JF_KNOWN_TYPE)) + return true; } return false; @@ -912,7 +1069,15 @@ ipcp_update_callgraph (void) { next = cs->next_caller; if (!ipcp_node_is_clone (cs->caller) && ipcp_need_redirect_p (cs)) - cgraph_redirect_edge_callee (cs, orig_node); + { + if (dump_file) + fprintf (dump_file, "Redirecting edge %s/%i -> %s/%i " + "back to %s/%i.", + cgraph_node_name (cs->caller), cs->caller->uid, + cgraph_node_name (cs->callee), cs->callee->uid, + cgraph_node_name (orig_node), orig_node->uid); + cgraph_redirect_edge_callee (cs, orig_node); + } } } } @@ -1031,6 +1196,57 @@ ipcp_estimate_cloning_cost (struct cgraph_node *node) return cost + 1; } +/* Walk indirect calls of NODE and if any polymorphic can be turned into a + direct one now, do so. */ + +static void +ipcp_process_devirtualization_opportunities (struct cgraph_node *node) +{ + struct ipa_node_params *info = IPA_NODE_REF (node); + struct cgraph_edge *ie, *next_ie; + + for (ie = node->indirect_calls; ie; ie = next_ie) + { + int param_index, types_count, j; + HOST_WIDE_INT token; + tree target; + + next_ie = ie->next_callee; + if (!ie->indirect_info->polymorphic) + continue; + param_index = ie->indirect_info->param_index; + if (param_index == -1 + || ipa_param_cannot_devirtualize_p (info, param_index) + || ipa_param_types_vec_empty (info, param_index)) + continue; + + token = ie->indirect_info->otr_token; + target = NULL_TREE; + types_count = VEC_length (tree, info->params[param_index].types); + for (j = 0; j < types_count; j++) + { + tree binfo = VEC_index (tree, info->params[param_index].types, j); + tree t = gimple_fold_obj_type_ref_known_binfo (token, binfo); + + if (!t) + { + target = NULL_TREE; + break; + } + else if (!target) + target = t; + else if (target != t) + { + target = NULL_TREE; + break; + } + } + + if (target) + ipa_make_edge_direct_to_target (ie, target); + } +} + /* Return number of live constant parameters. */ static int ipcp_const_param_count (struct cgraph_node *node) @@ -1043,9 +1259,11 @@ ipcp_const_param_count (struct cgraph_node *node) for (i = 0; i < count; i++) { struct ipcp_lattice *lat = ipcp_get_lattice (info, i); - if (ipcp_lat_is_insertable (lat) + if ((ipcp_lat_is_insertable (lat) /* Do not count obviously unused arguments. */ - && ipa_is_param_used (info, i)) + && ipa_is_param_used (info, i)) + || (!ipa_param_cannot_devirtualize_p (info, i) + && !ipa_param_types_vec_empty (info, i))) const_param++; } return const_param; @@ -1087,7 +1305,8 @@ ipcp_insert_stage (void) max_new_size = PARAM_VALUE (PARAM_LARGE_UNIT_INSNS); max_new_size = max_new_size * PARAM_VALUE (PARAM_IPCP_UNIT_GROWTH) / 100 + 1; - /* First collect all functions we proved to have constant arguments to heap. */ + /* First collect all functions we proved to have constant arguments to + heap. */ heap = fibheap_new (); for (node = cgraph_nodes; node; node = node->next) { @@ -1099,7 +1318,8 @@ ipcp_insert_stage (void) if (ipa_is_called_with_var_arguments (info)) continue; if (ipcp_const_param_count (node)) - node->aux = fibheap_insert (heap, ipcp_estimate_cloning_cost (node), node); + node->aux = fibheap_insert (heap, ipcp_estimate_cloning_cost (node), + node); } /* Now clone in priority order until code size growth limits are met or @@ -1183,6 +1403,8 @@ ipcp_insert_stage (void) if (node1 == NULL) continue; + ipcp_process_devirtualization_opportunities (node1); + if (dump_file) fprintf (dump_file, "versioned function %s with growth %i, overall %i\n", cgraph_node_name (node), (int)growth, (int)new_size); @@ -1245,18 +1467,30 @@ ipcp_driver (void) return 0; } -/* Note function body size. */ +/* 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_generate_summary (void) { + struct cgraph_node *node; + if (dump_file) fprintf (dump_file, "\nIPA constant propagation start:\n"); ipa_check_create_node_params (); ipa_check_create_edge_args (); ipa_register_cgraph_hooks (); - /* 1. Call the init stage to initialize - the ipa_node_params and ipa_edge_args structures. */ - ipcp_init_stage (); + + for (node = cgraph_nodes; node; node = node->next) + if (node->analyzed) + { + /* 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); + } } /* Write ipcp summary for nodes in SET. */ |