It is a good solution. Thanks, Feng ________________________________________ From: Martin Jambor <mjam...@suse.cz> Sent: Saturday, February 22, 2020 2:15 AM To: Feng Xue OS; Tamar Christina; Jan Hubicka; gcc-patches@gcc.gnu.org Cc: nd Subject: Re: [PATCH] Fix bug in recursiveness check for function to be cloned (ipa/pr93707)
Hi, On Thu, Feb 20 2020, Feng Xue OS wrote: > This is a simpel and nice fix, but could suppress some CP opportunities for > self-recursive call. Using the test case as example, the first should be a > for-all-context clone, and the call "recur_fn (i, 1, depth + 1)" is replaced > with > a newly created recursive node. Thus, in the next round of CP iteration, the > way to do CP for the 2nd arugment "1" is blocked, because its coming edge > can not pass check by cgraph_edge_brings_value_p(). > > +__attribute__((noinline)) static int recur_fn (int i, int j, int depth) > +{ > + if (depth > 10) > + return 1; > + > + data[i + j]++; > + > + if (depth & 3) > + recur_fn (i, 1, depth + 1); > + else > + recur_fn (i, j & 1, depth + 1); > + > + foo(); > + > + return i + j; > +} > + > +int caller (int v, int depth) > +{ > + recur_fn (1, v, depth); > + > + return 0; > +} > > >>However, I believe that his approach mostly papers over a bug that >>happens earlier, specifically that cgraph_edge_brings_value_p returned >>true for the self-recursive edge from all-context clone to itself, even >>though when evaluating the second argument. We assume that all context >>clones get at least as many constants as any other potential clone, but >>that does not work for self-recursive edges with pass-through parameters >>that that just pass along the received constant. > > The following check on value in cgraph_edge_brings_value_p could ensure > whether the value can arrive the dest node or not. If the value is a constant > without source, as above example "1", this is allowed. Otherwise, code snippet > enclosed by "if (caller_info->ipcp_orig_node)" could capture for-all-context > clone. there has not been any "following check" in your email but I believe I understand what you mean, and I added such check to my patch so that the edge carrying the non-pass through jump function was accepted by the cgraph_edge_brings_value_p predicate. However, that lead to the same assert in find_more_scalar_values_for_callers_subset because on that edge it tried to compute the depth + 1 value before it had any value to calculate it from. So after staring at the problem for another while I realized that the users self_recursive_pass_through_p and self_recursive_agg_pass_through_p would be OK if it returned false for self-recursive calls from/to a node which is already a clone - clones have their known constant values set at the point of their creation - and that doing so avoids this problem. So that is what the patch below does. I have still kept the cgraph_edge_brings_value_p hunks too, so that edges are collected reliably. Bootstrapped and tested on an x86_64-linux, LTO bootstrap underway. What do you think? Martin 2020-02-21 Martin Jambor <mjam...@suse.cz> Feng Xue <f...@os.amperecomputing.com> PR ipa/93707 * ipa-cp.c (same_node_or_its_all_contexts_clone_p): Replaced with new function calls_same_node_or_its_all_contexts_clone_p. (cgraph_edge_brings_value_p): Use it. (cgraph_edge_brings_value_p): Likewise. (self_recursive_pass_through_p): Return false if caller is a clone. (self_recursive_agg_pass_through_p): Likewise. testsuite/ * gcc.dg/ipa/pr93707.c: New test. --- gcc/ChangeLog | 11 +++++++++ gcc/ipa-cp.c | 38 +++++++++++++++++------------- gcc/testsuite/ChangeLog | 6 +++++ gcc/testsuite/gcc.dg/ipa/pr93707.c | 31 ++++++++++++++++++++++++ 4 files changed, 69 insertions(+), 17 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/ipa/pr93707.c diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 7c481407de9..a965cae4f07 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,14 @@ +2020-02-21 Martin Jambor <mjam...@suse.cz> + Feng Xue <f...@os.amperecomputing.com> + + PR ipa/93707 + * ipa-cp.c (same_node_or_its_all_contexts_clone_p): Replaced with + new function calls_same_node_or_its_all_contexts_clone_p. + (cgraph_edge_brings_value_p): Use it. + (cgraph_edge_brings_value_p): Likewise. + (self_recursive_pass_through_p): Return false if caller is a clone. + (self_recursive_agg_pass_through_p): Likewise. + 2020-02-17 Richard Biener <rguent...@suse.de> PR c/86134 diff --git a/gcc/ipa-cp.c b/gcc/ipa-cp.c index 4f5b72e6994..aa228df1204 100644 --- a/gcc/ipa-cp.c +++ b/gcc/ipa-cp.c @@ -4033,15 +4033,24 @@ edge_clone_summary_t::duplicate (cgraph_edge *src_edge, cgraph_edge *dst_edge, src_data->next_clone = dst_edge; } -/* Return true is NODE is DEST or its clone for all contexts. */ +/* Return true is CS calls DEST or its clone for all contexts, except for + self-recursive nodes in which it has to be DEST itself. */ static bool -same_node_or_its_all_contexts_clone_p (cgraph_node *node, cgraph_node *dest) +calls_same_node_or_its_all_contexts_clone_p (cgraph_edge *cs, cgraph_node *dest, + bool allow_recursion_to_clone) { - if (node == dest) + enum availability availability; + cgraph_node *callee = cs->callee->function_symbol (&availability); + + if (availability <= AVAIL_INTERPOSABLE) + return false; + if (callee == dest) return true; + if (!allow_recursion_to_clone && cs->caller == callee) + return false; - class ipa_node_params *info = IPA_NODE_REF (node); + class ipa_node_params *info = IPA_NODE_REF (callee); return info->is_all_contexts_clone && info->ipcp_orig_node == dest; } @@ -4053,11 +4062,8 @@ cgraph_edge_brings_value_p (cgraph_edge *cs, ipcp_value_source<tree> *src, cgraph_node *dest, ipcp_value<tree> *dest_val) { class ipa_node_params *caller_info = IPA_NODE_REF (cs->caller); - enum availability availability; - cgraph_node *real_dest = cs->callee->function_symbol (&availability); - if (availability <= AVAIL_INTERPOSABLE - || !same_node_or_its_all_contexts_clone_p (real_dest, dest) + if (!calls_same_node_or_its_all_contexts_clone_p (cs, dest, !src->val) || caller_info->node_dead) return false; @@ -4076,9 +4082,6 @@ cgraph_edge_brings_value_p (cgraph_edge *cs, ipcp_value_source<tree> *src, } else { - /* At the moment we do not propagate over arithmetic jump functions in - SCCs, so it is safe to detect self-feeding recursive calls in this - way. */ if (src->val == dest_val) return true; @@ -4113,11 +4116,8 @@ cgraph_edge_brings_value_p (cgraph_edge *cs, ipcp_value<ipa_polymorphic_call_context> *) { class ipa_node_params *caller_info = IPA_NODE_REF (cs->caller); - enum availability avail; - cgraph_node *real_dest = cs->callee->function_symbol (&avail); - if (avail <= AVAIL_INTERPOSABLE - || !same_node_or_its_all_contexts_clone_p (real_dest, dest) + if (!calls_same_node_or_its_all_contexts_clone_p (cs, dest, true) || caller_info->node_dead) return false; if (!src->val) @@ -4630,7 +4630,9 @@ self_recursive_pass_through_p (cgraph_edge *cs, ipa_jump_func *jfunc, int i, && availability > AVAIL_INTERPOSABLE && jfunc->type == IPA_JF_PASS_THROUGH && (!simple || ipa_get_jf_pass_through_operation (jfunc) == NOP_EXPR) - && ipa_get_jf_pass_through_formal_id (jfunc) == i) + && ipa_get_jf_pass_through_formal_id (jfunc) == i + && IPA_NODE_REF (cs->caller) + && !IPA_NODE_REF (cs->caller)->ipcp_orig_node) return true; return false; } @@ -4651,7 +4653,9 @@ self_recursive_agg_pass_through_p (cgraph_edge *cs, ipa_agg_jf_item *jfunc, && jfunc->offset == jfunc->value.load_agg.offset && (!simple || jfunc->value.pass_through.operation == NOP_EXPR) && jfunc->value.pass_through.formal_id == i - && useless_type_conversion_p (jfunc->value.load_agg.type, jfunc->type)) + && useless_type_conversion_p (jfunc->value.load_agg.type, jfunc->type) + && IPA_NODE_REF (cs->caller) + && !IPA_NODE_REF (cs->caller)->ipcp_orig_node) return true; return false; } diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index b326529ac75..e8c9f197e42 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,9 @@ +2020-02-18 Martin Jambor <mjam...@suse.cz> + Feng Xue <f...@os.amperecomputing.com> + + PR ipa/93707 + * gcc.dg/ipa/pr93707.c: New test. + 2020-02-17 Richard Biener <rguent...@suse.de> PR c/86134 diff --git a/gcc/testsuite/gcc.dg/ipa/pr93707.c b/gcc/testsuite/gcc.dg/ipa/pr93707.c new file mode 100644 index 00000000000..685fae45020 --- /dev/null +++ b/gcc/testsuite/gcc.dg/ipa/pr93707.c @@ -0,0 +1,31 @@ +/* { dg-do compile } */ +/* { dg-options "-O3 --param ipa-cp-eval-threshold=1 -fdump-ipa-cp" } */ + +int foo(); +int data[100]; + +__attribute__((noinline)) static int recur_fn (int i, int j, int depth) +{ + if (depth > 10) + return 1; + + data[i + j]++; + + if (depth & 3) + recur_fn (i, 1, depth + 1); + else + recur_fn (i, j & 1, depth + 1); + + foo(); + + return i + j; +} + +int caller (int v, int depth) +{ + recur_fn (1, v, depth); + + return 0; +} + +/* { dg-final { scan-ipa-dump-times "Clone of recur_fn/" 2 "cp" } } */ -- 2.25.0