If argument for a self-recursive call is a simple pass-through, the call
edge is also considered as source of any value originated from
non-recursive call to the function. Scalar pass-through and full aggregate
pass-through due to pointer pass-through have also been handled.
But we missed another kind of pass-through like below case, partial
aggregate pass-through. This patch is meant to fix the problem which
caused ICE as in 92794.
void foo(struct T *val_ptr)
{
struct T new_val;
new_val.field = val_ptr->field;
foo (&temp);
...
}
Bootstrapped/regtested on x86_64-linux and aarch64-linux.
2019-12-17 Feng Xue <f...@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.
Thanks,
Feng
From 42ba553ebf80eadb62619c5570a4b406f8c90c49 Mon Sep 17 00:00:00 2001
From: Feng Xue <f...@os.amperecomputing.com>
Date: Mon, 16 Dec 2019 20:33:36 +0800
Subject: [PATCH] Handle aggregate simple pass-through for self-recursive call
---
gcc/ipa-cp.c | 97 +++++++++++++++++++++++++-----
gcc/testsuite/gcc.dg/ipa/pr92794.c | 30 +++++++++
2 files changed, 111 insertions(+), 16 deletions(-)
create mode 100644 gcc/testsuite/gcc.dg/ipa/pr92794.c
diff --git a/gcc/ipa-cp.c b/gcc/ipa-cp.c
index 1a80ccbde2d..0e17fedd649 100644
--- a/gcc/ipa-cp.c
+++ b/gcc/ipa-cp.c
@@ -4564,6 +4564,23 @@ 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)
+{
+ if (cs->caller == cs->callee->function_symbol ()
+ && 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 +4773,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 +4853,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 +4963,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))
+ {
+ /* For a self-recursive call, if aggregate jump function is a
+ simple pass-through, the exact value it stands for is not
+ known, 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
{
- struct ipa_agg_value agg_value;
+ 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 +5006,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 +5102,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/gcc.dg/ipa/pr92794.c b/gcc/testsuite/gcc.dg/ipa/pr92794.c
new file mode 100644
index 00000000000..c3546177ccd
--- /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;
+}
--
2.17.1