Hi, this is a bit of aggregate IPA-CP that I missed to submit in last stage1 and that makes indirect call graph edges from IPA-CP clones direct if they call a known address loaded from an aggregate parameter.
The reason why ipa_get_indirect_edge_target is split into two is that unlike in the inlining case, this one has to understand the description of known aggregate values in clones which are different from aggregate jump functions (they are quite simpler). Otherwise the patch is hopefully quite straightforward. Bootstrapped and tested on x86_64-linux, OK for trunk? Thanks, Martin 2013-03-19 Martin Jambor <mjam...@suse.cz> * ipa-cp.c (ipa_get_indirect_edge_target): Renamed to ipa_get_indirect_edge_target_1, added parameter agg_reps and ability to process it. (ipa_get_indirect_edge_target): New function. (devirtualization_time_bonus): New parameter known_aggs, pass it to ipa_get_indirect_edge_target. Update all callers. (ipcp_discover_new_direct_edges): New parameter aggvals. Pass it to ipa_get_indirect_edge_target_1 instead of calling ipa_get_indirect_edge_target. (create_specialized_node): Pass aggvlas to ipcp_discover_new_direct_edges. testsuite/ * gcc.dg/ipa/ipcp-agg-9.c: New test. Index: src/gcc/ipa-cp.c =================================================================== --- src.orig/gcc/ipa-cp.c +++ src/gcc/ipa-cp.c @@ -1477,14 +1477,16 @@ propagate_constants_accross_call (struct } /* If an indirect edge IE can be turned into a direct one based on KNOWN_VALS - (which can contain both constants and binfos) or KNOWN_BINFOS (which can be - NULL) return the destination. */ + (which can contain both constants and binfos), KNOWN_BINFOS, KNOWN_AGGS or + AGG_REPS return the destination. The latter three can be NULL. If AGG_REPS + is not NULL, KNOWN_AGGS is ignored. */ -tree -ipa_get_indirect_edge_target (struct cgraph_edge *ie, - vec<tree> known_vals, - vec<tree> known_binfos, - vec<ipa_agg_jump_function_p> known_aggs) +static tree +ipa_get_indirect_edge_target_1 (struct cgraph_edge *ie, + vec<tree> known_vals, + vec<tree> known_binfos, + vec<ipa_agg_jump_function_p> known_aggs, + struct ipa_agg_replacement_value *agg_reps) { int param_index = ie->indirect_info->param_index; HOST_WIDE_INT token, anc_offset; @@ -1500,8 +1502,21 @@ ipa_get_indirect_edge_target (struct cgr if (ie->indirect_info->agg_contents) { - if (known_aggs.length () - > (unsigned int) param_index) + if (agg_reps) + { + t = NULL; + while (agg_reps) + { + if (agg_reps->index == param_index + && agg_reps->offset == ie->indirect_info->offset) + { + t = agg_reps->value; + break; + } + agg_reps = agg_reps->next; + } + } + else if (known_aggs.length () > (unsigned int) param_index) { struct ipa_agg_jump_function *agg; agg = known_aggs[param_index]; @@ -1556,13 +1571,29 @@ ipa_get_indirect_edge_target (struct cgr } } + +/* If an indirect edge IE can be turned into a direct one based on KNOWN_VALS + (which can contain both constants and binfos), KNOWN_BINFOS (which can be + NULL) or KNOWN_AGGS (which also can be NULL) return the destination. */ + +tree +ipa_get_indirect_edge_target (struct cgraph_edge *ie, + vec<tree> known_vals, + vec<tree> known_binfos, + vec<ipa_agg_jump_function_p> known_aggs) +{ + return ipa_get_indirect_edge_target_1 (ie, known_vals, known_binfos, + known_aggs, NULL); +} + /* Calculate devirtualization time bonus for NODE, assuming we know KNOWN_CSTS and KNOWN_BINFOS. */ static int devirtualization_time_bonus (struct cgraph_node *node, vec<tree> known_csts, - vec<tree> known_binfos) + vec<tree> known_binfos, + vec<ipa_agg_jump_function_p> known_aggs) { struct cgraph_edge *ie; int res = 0; @@ -1574,7 +1605,7 @@ devirtualization_time_bonus (struct cgra tree target; target = ipa_get_indirect_edge_target (ie, known_csts, known_binfos, - vNULL); + known_aggs); if (!target) continue; @@ -1818,7 +1849,8 @@ estimate_local_effects (struct cgraph_no cgraph_for_node_and_aliases (node, gather_caller_stats, &stats, false); estimate_ipcp_clone_size_and_time (node, known_csts, known_binfos, known_aggs_ptrs, &size, &time, &hints); - time -= devirtualization_time_bonus (node, known_csts, known_binfos); + time -= devirtualization_time_bonus (node, known_csts, known_binfos, + known_aggs_ptrs); time -= hint_time_bonus (hints); time -= removable_params_cost; size -= stats.n_calls * removable_params_cost; @@ -1895,7 +1927,8 @@ estimate_local_effects (struct cgraph_no known_aggs_ptrs, &size, &time, &hints); time_benefit = base_time - time - + devirtualization_time_bonus (node, known_csts, known_binfos) + + devirtualization_time_bonus (node, known_csts, known_binfos, + known_aggs_ptrs) + hint_time_bonus (hints) + removable_params_cost + emc; @@ -1957,7 +1990,8 @@ estimate_local_effects (struct cgraph_no known_aggs_ptrs, &size, &time, &hints); time_benefit = base_time - time - + devirtualization_time_bonus (node, known_csts, known_binfos) + + devirtualization_time_bonus (node, known_csts, known_binfos, + known_aggs_ptrs) + hint_time_bonus (hints); gcc_checking_assert (size >=0); if (size == 0) @@ -2240,7 +2274,8 @@ ipcp_propagate_stage (struct topo_info * static void ipcp_discover_new_direct_edges (struct cgraph_node *node, - vec<tree> known_vals) + vec<tree> known_vals, + struct ipa_agg_replacement_value *aggvals) { struct cgraph_edge *ie, *next_ie; bool found = false; @@ -2250,7 +2285,8 @@ ipcp_discover_new_direct_edges (struct c tree target; next_ie = ie->next_callee; - target = ipa_get_indirect_edge_target (ie, known_vals, vNULL, vNULL); + target = ipa_get_indirect_edge_target_1 (ie, known_vals, vNULL, vNULL, + aggvals); if (target) { ipa_make_edge_direct_to_target (ie, target); @@ -2660,7 +2696,7 @@ create_specialized_node (struct cgraph_n new_info->ipcp_orig_node = node; new_info->known_vals = known_vals; - ipcp_discover_new_direct_edges (new_node, known_vals); + ipcp_discover_new_direct_edges (new_node, known_vals, aggvals); callers.release (); return new_node; Index: src/gcc/testsuite/gcc.dg/ipa/ipcp-agg-9.c =================================================================== --- /dev/null +++ src/gcc/testsuite/gcc.dg/ipa/ipcp-agg-9.c @@ -0,0 +1,45 @@ +/* Verify that IPA-CP can make edges direct based on aggregate contents. */ +/* { dg-do compile } */ +/* { dg-options "-O3 -fno-early-inlining -fdump-ipa-cp -fdump-ipa-inline" } */ + +struct S +{ + int i; + void (*f)(struct S *); + unsigned u; +}; + +struct U +{ + struct U *next; + struct S s; + short a[8]; +}; + +extern void non_existent(struct S *p, int); + +static void hooray1 (struct S *p) +{ + non_existent (p, 1); +} + +static __attribute__ ((noinline)) +void hiphip1 (struct S *p) +{ + p->f (p); +} + +int test1 (void) +{ + struct S s; + s.i = 1234; + s.f = hooray1; + s.u = 1001; + hiphip1 (&s); + return 0; +} + +/* { dg-final { scan-ipa-dump "ipa-prop: Discovered an indirect call to a known target" "cp" } } */ +/* { dg-final { scan-ipa-dump "hooray1\[^\\n\]*inline copy in hiphip1" "inline" } } */ +/* { dg-final { cleanup-ipa-dump "cp" } } */ +/* { dg-final { cleanup-ipa-dump "inline" } } */