diff options
-rw-r--r-- | gcc/ChangeLog | 11 | ||||
-rw-r--r-- | gcc/ipa-cp.c | 99 | ||||
-rw-r--r-- | gcc/testsuite/ChangeLog | 5 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/ipa/pr92794.c | 30 |
4 files changed, 129 insertions, 16 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 5927823..e52d056 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,14 @@ +2019-12-19 Feng Xue <fxue@os.amperecomputing.com> + + PR ipa/92794 + * ipa-cp.c (self_recursive_agg_pass_through_p): New function. + (intersect_with_plats): Use error_mark_node as place holder + when aggregate jump function is simple pass-through for + self-recursive call. + (intersect_with_agg_replacements): Likewise. + (intersect_aggregates_with_edge): Likewise. + (find_aggregate_values_for_callers_subset): Likewise. + 2019-12-18 David Malcolm <dmalcolm@redhat.com> * common.opt (fdiagnostics-show-cwe): Add. diff --git a/gcc/ipa-cp.c b/gcc/ipa-cp.c index 243b064..126d154 100644 --- a/gcc/ipa-cp.c +++ b/gcc/ipa-cp.c @@ -4564,6 +4564,25 @@ self_recursive_pass_through_p (cgraph_edge *cs, ipa_jump_func *jfunc, int i) return false; } +/* Return true, if JFUNC, which describes a part of an aggregate represented + or pointed to by the i-th parameter of call CS, is a simple no-operation + pass-through function to itself. */ + +static bool +self_recursive_agg_pass_through_p (cgraph_edge *cs, ipa_agg_jf_item *jfunc, + int i) +{ + enum availability availability; + if (cs->caller == cs->callee->function_symbol (&availability) + && availability > AVAIL_INTERPOSABLE + && jfunc->jftype == IPA_JF_LOAD_AGG + && jfunc->offset == jfunc->value.load_agg.offset + && jfunc->value.pass_through.operation == NOP_EXPR + && jfunc->value.pass_through.formal_id == i) + return true; + return false; +} + /* Given a NODE, and a subset of its CALLERS, try to populate blanks slots in KNOWN_CSTS with constants that are also known for all of the CALLERS. */ @@ -4756,10 +4775,19 @@ intersect_with_plats (class ipcp_param_lattices *plats, if (aglat->offset - offset == item->offset) { gcc_checking_assert (item->value); - if (aglat->is_single_const () - && values_equal_for_ipcp_p (item->value, - aglat->values->value)) - found = true; + if (aglat->is_single_const ()) + { + tree value = aglat->values->value; + + if (values_equal_for_ipcp_p (item->value, value)) + found = true; + else if (item->value == error_mark_node) + { + /* Replace unknown place holder value with real one. */ + item->value = value; + found = true; + } + } break; } aglat = aglat->next; @@ -4827,6 +4855,12 @@ intersect_with_agg_replacements (struct cgraph_node *node, int index, { if (values_equal_for_ipcp_p (item->value, av->value)) found = true; + else if (item->value == error_mark_node) + { + /* Replace place holder value with real one. */ + item->value = av->value; + found = true; + } break; } } @@ -4931,17 +4965,31 @@ intersect_aggregates_with_edge (struct cgraph_edge *cs, int index, for (unsigned i = 0; i < jfunc->agg.items->length (); i++) { struct ipa_agg_jf_item *agg_item = &(*jfunc->agg.items)[i]; - tree value = ipa_agg_value_from_node (caller_info, cs->caller, - agg_item); - if (value) + struct ipa_agg_value agg_value; + + if (self_recursive_agg_pass_through_p (cs, agg_item, index)) { - struct ipa_agg_value agg_value; + /* For a self-recursive call, if aggregate jump function is a + simple pass-through, the exact value that it stands for is + not known at this point, which must comes from other call + sites. But we still need to add a place holder in value + sets to indicate it, here we use error_mark_node to + represent the special unknown value, which will be replaced + with real one during later intersecting operations. */ + agg_value.value = error_mark_node; + } + else + { + tree value = ipa_agg_value_from_node (caller_info, cs->caller, + agg_item); + if (!value) + continue; - agg_value.offset = agg_item->offset; agg_value.value = value; - - inter.safe_push (agg_value); } + + agg_value.offset = agg_item->offset; + inter.safe_push (agg_value); } else FOR_EACH_VEC_ELT (inter, k, item) @@ -4960,11 +5008,27 @@ intersect_aggregates_with_edge (struct cgraph_edge *cs, int index, break; if (ti->offset == item->offset) { - tree value = ipa_agg_value_from_node (caller_info, - cs->caller, ti); - if (value - && values_equal_for_ipcp_p (item->value, value)) - found = true; + tree value; + + if (self_recursive_agg_pass_through_p (cs, ti, index)) + { + /* A simple aggregate pass-through in self-recursive + call should lead to same value. */ + found = true; + } + else if ((value = ipa_agg_value_from_node (caller_info, + cs->caller, ti))) + { + if (values_equal_for_ipcp_p (item->value, value)) + found = true; + else if (item->value == error_mark_node) + { + /* Replace unknown place holder value with real + one. */ + item->value = value; + found = true; + } + } break; } l++; @@ -5040,6 +5104,9 @@ find_aggregate_values_for_callers_subset (struct cgraph_node *node, if (!item->value) continue; + /* All values must be real values, not unknown place holders. */ + gcc_assert (item->value != error_mark_node); + v = ggc_alloc<ipa_agg_replacement_value> (); v->index = i; v->offset = item->offset; diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 18b4ba3..e66980e 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2019-12-19 Feng Xue <fxue@os.amperecomputing.com> + + PR ipa/92794 + * gcc.dg/ipa/92794.c: New test. + 2019-12-18 David Malcolm <dmalcolm@redhat.com> * gcc.dg/plugin/diagnostic-test-metadata.c: New test. diff --git a/gcc/testsuite/gcc.dg/ipa/pr92794.c b/gcc/testsuite/gcc.dg/ipa/pr92794.c new file mode 100644 index 0000000..c354617 --- /dev/null +++ b/gcc/testsuite/gcc.dg/ipa/pr92794.c @@ -0,0 +1,30 @@ +/* { dg-do compile } */ +/* { dg-options "-O3 --param ipa-cp-eval-threshold=1" } */ + +int data[100]; +int depth = 0; + +int recur_fn (int *__restrict p) +{ + int i = *p; + + if (depth++ > 6) + return 10; + + data[i] = i; + + recur_fn (&i); + + depth--; + + return i; +} + +int main () +{ + int i = 1; + + recur_fn (&i); + + return 0; +} |