aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/ChangeLog11
-rw-r--r--gcc/ipa-cp.c99
-rw-r--r--gcc/testsuite/ChangeLog5
-rw-r--r--gcc/testsuite/gcc.dg/ipa/pr92794.c30
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;
+}