From 40ff412bfef584461ddc16fbbaaad3275a294d64 Mon Sep 17 00:00:00 2001
From: Feng Xue <fxue@os.amperecomputing.com>
Date: Wed, 12 Feb 2020 13:04:33 -0500
Subject: [PATCH] Fix bug in recursiveness check for function in clone (PR
 ipa/93707)

---
 gcc/ipa-cp.c                       | 54 +++++++++++++++++-------------
 gcc/testsuite/gcc.dg/ipa/pr93707.c | 29 ++++++++++++++++
 2 files changed, 60 insertions(+), 23 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/ipa/pr93707.c

diff --git a/gcc/ipa-cp.c b/gcc/ipa-cp.c
index 4f5b72e6994..9fbeeae9e77 100644
--- a/gcc/ipa-cp.c
+++ b/gcc/ipa-cp.c
@@ -4617,17 +4617,21 @@ create_specialized_node (struct cgraph_node *node,
   return new_node;
 }
 
-/* Return true, if JFUNC, which describes a i-th parameter of call CS, is a
-   pass-through function to itself.  When SIMPLE is true, further check if
-   JFUNC is a simple no-operation pass-through.  */
+/* Given an edge CS, along which we will do cloning for NODE, return true,
+   if CS represents a self-recursive call to NODE, and if JFUNC, which
+   describes the i-th argument of CS, is a pass-through jump function to the
+   i-th parameter of NODE.  When SIMPLE is true, further check if JFUNC is a
+   simple no-operation pass-through.  */
 
 static bool
-self_recursive_pass_through_p (cgraph_edge *cs, ipa_jump_func *jfunc, int i,
-			       bool simple = true)
-{
-  enum availability availability;
-  if (cs->caller == cs->callee->function_symbol (&availability)
-      && availability > AVAIL_INTERPOSABLE
+self_recursive_pass_through_p (cgraph_edge *cs, cgraph_node *node,
+			       ipa_jump_func *jfunc,
+			       int i, bool simple = true)
+{
+   /* CS could be created from a for-all-contexts clone, thus NODE might not
+      be callee of CS.  Here we could not resort to ordinary way of comparing
+      caller and callee of CS to check recursiveness.  */
+  if (cs->caller == node
       && 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)
@@ -4635,18 +4639,19 @@ 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 pass-through function
-   to itself.  When SIMPLE is true, further check if JFUNC is a simple
-   no-operation pass-through.  */
+/* Given an edge CS, along which we will do cloning for NODE, return true,
+   if CS represents a self-recursive call to NODE, and if JFUNC, which
+   describes a part of an aggregate represented or pointed to by the i-th
+   argument of CS, is a pass-through jump function to same aggregate part of
+   the i-th parameter of NODE.  When SIMPLE is true, further check if JFUNC
+   is a simple no-operation pass-through.  */
 
 static bool
-self_recursive_agg_pass_through_p (cgraph_edge *cs, ipa_agg_jf_item *jfunc,
+self_recursive_agg_pass_through_p (cgraph_edge *cs, cgraph_node *node,
+				   ipa_agg_jf_item *jfunc,
 				   int i, bool simple = true)
 {
-  enum availability availability;
-  if (cs->caller == cs->callee->function_symbol (&availability)
-      && availability > AVAIL_INTERPOSABLE
+  if (cs->caller == node
       && jfunc->jftype == IPA_JF_LOAD_AGG
       && jfunc->offset == jfunc->value.load_agg.offset
       && (!simple || jfunc->value.pass_through.operation == NOP_EXPR)
@@ -4704,7 +4709,7 @@ find_more_scalar_values_for_callers_subset (struct cgraph_node *node,
 
 	     Given that i is 0, recursive propagation via (i & 1) also gets
 	     0.  */
-	  if (self_recursive_pass_through_p (cs, jump_func, i, false))
+	  if (self_recursive_pass_through_p (cs, node, jump_func, i, false))
 	    {
 	      gcc_assert (newval);
 	      t = ipa_get_jf_arith_result (
@@ -4952,7 +4957,9 @@ intersect_with_agg_replacements (struct cgraph_node *node, int index,
    whatsoever, return a released vector.  */
 
 static vec<ipa_agg_value>
-intersect_aggregates_with_edge (struct cgraph_edge *cs, int index,
+intersect_aggregates_with_edge (struct cgraph_edge *cs,
+				struct cgraph_node *node,
+				int index,
 				vec<ipa_agg_value> inter)
 {
   struct ipa_jump_func *jfunc;
@@ -5085,7 +5092,7 @@ intersect_aggregates_with_edge (struct cgraph_edge *cs, int index,
 
 		       Given that *i is 0, recursive propagation via (*i & 1)
 		       also gets 0.  */
-		    if (self_recursive_agg_pass_through_p (cs, ti, index,
+		    if (self_recursive_agg_pass_through_p (cs, node, ti, index,
 							   false))
 		      value = ipa_get_jf_arith_result (
 					ti->value.pass_through.operation,
@@ -5156,11 +5163,11 @@ find_aggregate_values_for_callers_subset (struct cgraph_node *node,
 	{
 	  struct ipa_jump_func *jfunc
 	    = ipa_get_ith_jump_func (IPA_EDGE_REF (cs), i);
-	  if (self_recursive_pass_through_p (cs, jfunc, i)
+	  if (self_recursive_pass_through_p (cs, node, jfunc, i)
 	      && (!plats->aggs_by_ref
 		  || ipa_get_jf_pass_through_agg_preserved (jfunc)))
 	    continue;
-	  inter = intersect_aggregates_with_edge (cs, i, inter);
+	  inter = intersect_aggregates_with_edge (cs, node, i, inter);
 
 	  if (!inter.exists ())
 	    goto next_param;
@@ -5265,7 +5272,8 @@ cgraph_edge_brings_all_agg_vals_for_node (struct cgraph_edge *cs,
       if (plats->aggs_bottom)
 	return false;
 
-      vec<ipa_agg_value> values = intersect_aggregates_with_edge (cs, i, vNULL);
+      vec<ipa_agg_value> values
+		= intersect_aggregates_with_edge (cs, node, i, vNULL);
       if (!values.exists ())
 	return false;
 
diff --git a/gcc/testsuite/gcc.dg/ipa/pr93707.c b/gcc/testsuite/gcc.dg/ipa/pr93707.c
new file mode 100644
index 00000000000..e200a3a432b
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/pr93707.c
@@ -0,0 +1,29 @@
+/* { dg-do compile } */
+/* { dg-options "-O3 --param ipa-cp-eval-threshold=1" } */
+
+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;
+}
-- 
2.17.1

