Fix handling of static chain in modref

Message ID 20211124213047.GB13308@kam.mff.cuni.cz
State Committed
Commit 16e85390507ea92331c9052393b591202007f5ab
Headers
Series Fix handling of static chain in modref |

Commit Message

Jan Hubicka Nov. 24, 2021, 9:30 p.m. UTC
  Hi,
this patch fixes wrong code issue where modref did not propagate flags
for static chain in ipa_merge_modref_summary_after_inlininig.  It is a
place I missed to update in original patch extending return slot
tracking to static chain.  Unlike return slot we need to propagate flags
here (return slot is write only parameter and does not need it)

Bootstrapped/regtested x86_64-linux, comitted.
gcc/ChangeLog:

2021-11-24  Jan Hubicka  <hubicka@ucw.cz>

	* ipa-modref.c (implicit_eaf_flags_for_edge_and_arg): Break out from...
	(modref_merge_call_site_flags): ... here.
	(ipa_merge_modref_summary_after_inlining): Use it.

gcc/testsuite/ChangeLog:

2021-11-24  Jan Hubicka  <hubicka@ucw.cz>

	* gcc.c-torture/execute/pr103405.c: New test.
  

Patch

diff --git a/gcc/ipa-modref.c b/gcc/ipa-modref.c
index 923ae6c1dd3..c2edc0d28a6 100644
--- a/gcc/ipa-modref.c
+++ b/gcc/ipa-modref.c
@@ -4827,6 +4827,30 @@  modref_propagate_dump_scc (cgraph_node *component_node)
       }
 }
 
+/* Determine EAF flags know for call E with CALLEE_ECF_FLAGS and ARG.  */
+
+int
+implicit_eaf_flags_for_edge_and_arg (cgraph_edge *e, int callee_ecf_flags,
+				     bool ignore_stores, int arg)
+{
+  /* Returning the value is already accounted to at local propagation.  */
+  int implicit_flags = EAF_NOT_RETURNED_DIRECTLY
+		       | EAF_NOT_RETURNED_INDIRECTLY;
+  if (ignore_stores)
+     implicit_flags |= ignore_stores_eaf_flags;
+  if (callee_ecf_flags & ECF_PURE)
+    implicit_flags |= implicit_pure_eaf_flags;
+  if (callee_ecf_flags & (ECF_CONST | ECF_NOVOPS))
+    implicit_flags |= implicit_const_eaf_flags;
+  class fnspec_summary *fnspec_sum = fnspec_summaries->get (e);
+  if (fnspec_sum)
+    {
+      attr_fnspec fnspec (fnspec_sum->fnspec);
+      implicit_flags |= fnspec.arg_eaf_flags (arg);
+    }
+  return implicit_flags;
+}
+
 /* Process escapes in SUM and merge SUMMARY to CUR_SUMMARY
    and SUMMARY_LTO to CUR_SUMMARY_LTO.
    Return true if something changed.  */
@@ -4857,9 +4881,8 @@  modref_merge_call_site_flags (escape_summary *sum,
     {
       int flags = 0;
       int flags_lto = 0;
-      /* Returning the value is already accounted to at local propagation.  */
-      int implicit_flags = EAF_NOT_RETURNED_DIRECTLY
-			   | EAF_NOT_RETURNED_INDIRECTLY;
+      int implicit_flags = implicit_eaf_flags_for_edge_and_arg
+				(e, callee_ecf_flags, ignore_stores, ee->arg);
 
       if (summary && ee->arg < summary->arg_flags.length ())
 	flags = summary->arg_flags[ee->arg];
@@ -4995,6 +5018,7 @@  modref_propagate_flags_in_scc (cgraph_node *component_node)
 	      if (ecf_flags & (ECF_CONST | ECF_NOVOPS)
 		  || !callee_edge->inline_failed)
 		continue;
+
 	      /* Get the callee and its summary.  */
 	      enum availability avail;
 	      callee = callee_edge->callee->function_or_virtual_thunk_symbol
@@ -5081,6 +5105,9 @@  ipa_merge_modref_summary_after_inlining (cgraph_edge *edge)
   class modref_summary_lto *callee_info_lto
 		 = summaries_lto ? summaries_lto->get (edge->callee) : NULL;
   int flags = flags_from_decl_or_type (edge->callee->decl);
+  /* Combine in outer flags.  */
+  for (cgraph_node *n = edge->caller; n->inlined_to; n = n->callers->caller)
+    flags |= flags_from_decl_or_type (edge->callee->decl);
   bool ignore_stores = ignore_stores_p (edge->caller->decl, flags);
 
   if (!callee_info && to_info)
@@ -5148,10 +5175,11 @@  ipa_merge_modref_summary_after_inlining (cgraph_edge *edge)
     FOR_EACH_VEC_ELT (sum->esc, i, ee)
       {
 	bool needed = false;
-	/* TODO: We do not have jump functions for return slots, so we
-	   never propagate them to outer function.  */
-	if (ee->parm_index < 0)
-	  continue;
+	int implicit_flags = implicit_eaf_flags_for_edge_and_arg
+				(edge, flags, ignore_stores,
+				 ee->arg);
+	if (!ee->direct)
+	  implicit_flags = deref_flags (implicit_flags, ignore_stores);
 	if (to_info && (int)to_info->arg_flags.length () > ee->parm_index)
 	  {
 	    int flags = callee_info
@@ -5159,11 +5187,14 @@  ipa_merge_modref_summary_after_inlining (cgraph_edge *edge)
 			? callee_info->arg_flags[ee->arg] : 0;
 	    if (!ee->direct)
 	      flags = deref_flags (flags, ignore_stores);
-	    else if (ignore_stores)
-	      flags |= ignore_stores_eaf_flags;
-	    flags |= ee->min_flags;
-	    to_info->arg_flags[ee->parm_index] &= flags;
-	    if (to_info->arg_flags[ee->parm_index])
+	    flags |= ee->min_flags | implicit_flags;
+	    eaf_flags_t &f = ee->parm_index == MODREF_RETSLOT_PARM
+			     ? to_info->retslot_flags
+			     : ee->parm_index == MODREF_STATIC_CHAIN_PARM
+			     ? to_info->static_chain_flags
+			     : to_info->arg_flags[ee->parm_index];
+	    f &= flags;
+	    if (f)
 	      needed = true;
 	  }
 	if (to_info_lto
@@ -5174,11 +5205,14 @@  ipa_merge_modref_summary_after_inlining (cgraph_edge *edge)
 			? callee_info_lto->arg_flags[ee->arg] : 0;
 	    if (!ee->direct)
 	      flags = deref_flags (flags, ignore_stores);
-	    else if (ignore_stores)
-	      flags |= ignore_stores_eaf_flags;
-	    flags |= ee->min_flags;
-	    to_info_lto->arg_flags[ee->parm_index] &= flags;
-	    if (to_info_lto->arg_flags[ee->parm_index])
+	    flags |= ee->min_flags | implicit_flags;
+	    eaf_flags_t &f = ee->parm_index == MODREF_RETSLOT_PARM
+			     ? to_info_lto->retslot_flags
+			     : ee->parm_index == MODREF_STATIC_CHAIN_PARM
+			     ? to_info_lto->static_chain_flags
+			     : to_info_lto->arg_flags[ee->parm_index];
+	    f &= flags;
+	    if (f)
 	      needed = true;
 	  }
 	struct escape_map entry = {ee->parm_index, ee->direct};
diff --git a/gcc/testsuite/gcc.c-torture/execute/pr103405.c b/gcc/testsuite/gcc.c-torture/execute/pr103405.c
new file mode 100644
index 00000000000..f6005dc2983
--- /dev/null
+++ b/gcc/testsuite/gcc.c-torture/execute/pr103405.c
@@ -0,0 +1,37 @@ 
+typedef __SIZE_TYPE__ size_t;
+void *malloc(size_t);
+
+static inline int *starter(int a)
+{
+    int *b = malloc(sizeof(int));
+    *b = a;
+    return b;
+}
+
+static inline _Bool equal(int *l, int *r)
+{
+    if (l == 0)
+      __builtin_abort();
+    if (r == 0)
+      __builtin_abort();
+    return *r == *l;
+}
+
+int main(void)
+{
+  int *i;
+  int *j;
+  void check(_Bool a)
+  {
+    _Bool t = equal(i, j);
+    if (a && t) __builtin_abort ();
+    _Bool t1 = equal(i, j);
+    if (!a && !t1) __builtin_abort ();
+  }
+  i = starter(1);
+  j = starter(0);
+  check(1);
+  i = starter(0);
+  check(0);
+
+}