Finish lto parts of kill analysis

Jan Hubicka hubicka@kam.mff.cuni.cz
Wed Nov 17 09:33:19 GMT 2021


Hi,
this patch adds the IPA part of modref kill analysis.  It just copies of
what local code did alrady.  I did not manage to push out all patches
for modref I planned and I will wait for next stage1.  This one however
I would like to push since it is quite simple and it makes no sense to
leave the ipa bits being collected but unused.

Bootstrapped/regtested x86_64-linux. I will commit it tonight if there
are no complains.

Honza

gcc/ChangeLog:

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

	* ipa-modref-tree.c: Include cgraph.h and tree-streamer.h.
	(modref_access_node::stream_out): New member function.
	(modref_access_node::stream_in): New member function.
	* ipa-modref-tree.h (modref_access_node::stream_out,
	modref_access_node::stream_in): Declare.
	* ipa-modref.c (modref_summary_lto::useful_p): Free useless kills.
	(modref_summary_lto::dump): Dump kills.
	(analyze_store): Record kills for LTO
	(analyze_stmt): Likewise.
	(modref_summaries_lto::duplicate): Duplicate kills.
	(write_modref_records): Use new stream_out member function.
	(read_modref_records): Likewise.
	(modref_write): Stream out kills.
	(read_section): Stream in kills
	(remap_kills): New function.
	(update_signature): Use it.

diff --git a/gcc/ipa-modref-tree.c b/gcc/ipa-modref-tree.c
index bbe23a5a211..ece42ade225 100644
--- a/gcc/ipa-modref-tree.c
+++ b/gcc/ipa-modref-tree.c
@@ -27,6 +27,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "selftest.h"
 #include "tree-ssa-alias.h"
 #include "gimple.h"
+#include "cgraph.h"
+#include "tree-streamer.h"
 
 /* Return true if both accesses are the same.  */
 bool
@@ -458,6 +460,50 @@ modref_access_node::try_merge_with (vec <modref_access_node, va_gc> *&accesses,
       i++;
 }
 
+/* Stream out to OB.  */
+
+void
+modref_access_node::stream_out (struct output_block *ob) const
+{
+  streamer_write_hwi (ob, parm_index);
+  if (parm_index != -1)
+    {
+      streamer_write_uhwi (ob, parm_offset_known);
+      if (parm_offset_known)
+	{
+	  streamer_write_poly_int64 (ob, parm_offset);
+	  streamer_write_poly_int64 (ob, offset);
+	  streamer_write_poly_int64 (ob, size);
+	  streamer_write_poly_int64 (ob, max_size);
+	}
+    }
+}
+
+modref_access_node
+modref_access_node::stream_in (struct lto_input_block *ib)
+{
+  int parm_index = streamer_read_hwi (ib);
+  bool parm_offset_known = false;
+  poly_int64 parm_offset = 0;
+  poly_int64 offset = 0;
+  poly_int64 size = -1;
+  poly_int64 max_size = -1;
+
+  if (parm_index != -1)
+    {
+      parm_offset_known = streamer_read_uhwi (ib);
+      if (parm_offset_known)
+	{
+	  parm_offset = streamer_read_poly_int64 (ib);
+	  offset = streamer_read_poly_int64 (ib);
+	  size = streamer_read_poly_int64 (ib);
+	  max_size = streamer_read_poly_int64 (ib);
+	}
+    }
+  return {offset, size, max_size, parm_offset, parm_index,
+	  parm_offset_known, false};
+}
+
 /* Insert access with OFFSET and SIZE.
    Collapse tree if it has more than MAX_ACCESSES entries.
    If RECORD_ADJUSTMENTs is true avoid too many interval extensions.
diff --git a/gcc/ipa-modref-tree.h b/gcc/ipa-modref-tree.h
index 1bf2aa8460e..0a097349ebd 100644
--- a/gcc/ipa-modref-tree.h
+++ b/gcc/ipa-modref-tree.h
@@ -99,6 +99,10 @@ struct GTY(()) modref_access_node
   tree get_call_arg (const gcall *stmt) const;
   /* Build ao_ref corresponding to the access and return true if succesful.  */
   bool get_ao_ref (const gcall *stmt, class ao_ref *ref) const;
+  /* Stream access to OB.  */
+  void stream_out (struct output_block *ob) const;
+  /* Stream access in from IB.  */
+  static modref_access_node stream_in (struct lto_input_block *ib);
   /* Insert A into vector ACCESSES.  Limit size of vector to MAX_ACCESSES and
      if RECORD_ADJUSTMENT is true keep track of adjustment counts.
      Return 0 if nothing changed, 1 is insertion suceeded and -1 if failed.  */
diff --git a/gcc/ipa-modref.c b/gcc/ipa-modref.c
index 90cd1be764c..9ceecdd479f 100644
--- a/gcc/ipa-modref.c
+++ b/gcc/ipa-modref.c
@@ -410,6 +410,8 @@ modref_summary_lto::useful_p (int ecf_flags, bool check_flags)
 	    && (ecf_flags & ECF_LOOPING_CONST_OR_PURE));
   if (loads && !loads->every_base)
     return true;
+  else
+    kills.release ();
   if (ecf_flags & ECF_PURE)
     return ((!side_effects || !nondeterministic)
 	    && (ecf_flags & ECF_LOOPING_CONST_OR_PURE));
@@ -634,6 +636,15 @@ modref_summary_lto::dump (FILE *out)
   dump_lto_records (loads, out);
   fprintf (out, "  stores:\n");
   dump_lto_records (stores, out);
+  if (kills.length ())
+    {
+      fprintf (out, "  kills:\n");
+      for (auto kill : kills)
+	{
+	  fprintf (out, "    ");
+	  kill.dump (out);
+	}
+    }
   if (writes_errno)
     fprintf (out, "  Writes errno\n");
   if (side_effects)
@@ -1527,15 +1538,17 @@ analyze_store (gimple *stmt, tree, tree op, void *data)
     record_access (summary->stores, &r, a);
   if (summary_lto)
     record_access_lto (summary_lto->stores, &r, a);
-  if (summary
-      && ((summary_ptrs *)data)->always_executed
+  if (((summary_ptrs *)data)->always_executed
       && a.useful_for_kill_p ()
       && (!cfun->can_throw_non_call_exceptions
 	  || !stmt_could_throw_p (cfun, stmt)))
     {
       if (dump_file)
 	fprintf (dump_file, "   - Recording kill\n");
-      modref_access_node::insert_kill (summary->kills, a, false);
+      if (summary)
+	modref_access_node::insert_kill (summary->kills, a, false);
+      if (summary_lto)
+	modref_access_node::insert_kill (summary_lto->kills, a, false);
     }
   return false;
 }
@@ -1554,8 +1567,7 @@ analyze_stmt (modref_summary *summary, modref_summary_lto *summary_lto,
      Similar logic is in ipa-pure-const.c.  */
   if ((ipa || cfun->after_inlining) && gimple_clobber_p (stmt))
     {
-      if (summary
-	  && always_executed && record_access_p (gimple_assign_lhs (stmt)))
+      if (always_executed && record_access_p (gimple_assign_lhs (stmt)))
 	{
 	  ao_ref r;
 	  ao_ref_init (&r, gimple_assign_lhs (stmt));
@@ -1564,7 +1576,10 @@ analyze_stmt (modref_summary *summary, modref_summary_lto *summary_lto,
 	    {
 	      if (dump_file)
 		fprintf (dump_file, "   - Recording kill\n");
-	      modref_access_node::insert_kill (summary->kills, a, false);
+	      if (summary)
+		modref_access_node::insert_kill (summary->kills, a, false);
+	      if (summary_lto)
+		modref_access_node::insert_kill (summary_lto->kills, a, false);
 	    }
 	}
       return true;
@@ -3270,6 +3285,8 @@ modref_summaries_lto::duplicate (cgraph_node *, cgraph_node *,
 			 src_data->loads->max_refs,
 			 src_data->loads->max_accesses);
   dst_data->loads->copy_from (src_data->loads);
+  dst_data->kills.reserve_exact (src_data->kills.length ());
+  dst_data->kills.splice (src_data->kills);
   dst_data->writes_errno = src_data->writes_errno;
   dst_data->side_effects = src_data->side_effects;
   dst_data->nondeterministic = src_data->nondeterministic;
@@ -3324,40 +3341,21 @@ write_modref_records (modref_records_lto *tt, struct output_block *ob)
 
   streamer_write_uhwi (ob, tt->every_base);
   streamer_write_uhwi (ob, vec_safe_length (tt->bases));
-  size_t i;
-  modref_base_node <tree> *base_node;
-  FOR_EACH_VEC_SAFE_ELT (tt->bases, i, base_node)
+  for (auto base_node : tt->bases)
     {
       stream_write_tree (ob, base_node->base, true);
 
       streamer_write_uhwi (ob, base_node->every_ref);
       streamer_write_uhwi (ob, vec_safe_length (base_node->refs));
 
-      size_t j;
-      modref_ref_node <tree> *ref_node;
-      FOR_EACH_VEC_SAFE_ELT (base_node->refs, j, ref_node)
+      for (auto ref_node : base_node->refs)
 	{
 	  stream_write_tree (ob, ref_node->ref, true);
 	  streamer_write_uhwi (ob, ref_node->every_access);
 	  streamer_write_uhwi (ob, vec_safe_length (ref_node->accesses));
 
-	  size_t k;
-	  modref_access_node *access_node;
-	  FOR_EACH_VEC_SAFE_ELT (ref_node->accesses, k, access_node)
-	    {
-	      streamer_write_hwi (ob, access_node->parm_index);
-	      if (access_node->parm_index != -1)
-		{
-		  streamer_write_uhwi (ob, access_node->parm_offset_known);
-		  if (access_node->parm_offset_known)
-		    {
-		      streamer_write_poly_int64 (ob, access_node->parm_offset);
-		      streamer_write_poly_int64 (ob, access_node->offset);
-		      streamer_write_poly_int64 (ob, access_node->size);
-		      streamer_write_poly_int64 (ob, access_node->max_size);
-		    }
-		}
-	    }
+	  for (auto access_node : ref_node->accesses)
+	    access_node.stream_out (ob);
 	}
     }
 }
@@ -3469,26 +3467,7 @@ read_modref_records (lto_input_block *ib, struct data_in *data_in,
 
 	  for (size_t k = 0; k < naccesses; k++)
 	    {
-	      int parm_index = streamer_read_hwi (ib);
-	      bool parm_offset_known = false;
-	      poly_int64 parm_offset = 0;
-	      poly_int64 offset = 0;
-	      poly_int64 size = -1;
-	      poly_int64 max_size = -1;
-
-	      if (parm_index != -1)
-		{
-		  parm_offset_known = streamer_read_uhwi (ib);
-		  if (parm_offset_known)
-		    {
-		      parm_offset = streamer_read_poly_int64 (ib);
-		      offset = streamer_read_poly_int64 (ib);
-		      size = streamer_read_poly_int64 (ib);
-		      max_size = streamer_read_poly_int64 (ib);
-		    }
-		}
-	      modref_access_node a = {offset, size, max_size, parm_offset,
-				      parm_index, parm_offset_known, false};
+	      modref_access_node a = modref_access_node::stream_in (ib);
 	      if (nolto_ref_node)
 		nolto_ref_node->insert_access (a, max_accesses, false);
 	      if (lto_ref_node)
@@ -3599,6 +3578,9 @@ modref_write ()
 
 	  write_modref_records (r->loads, ob);
 	  write_modref_records (r->stores, ob);
+	  streamer_write_uhwi (ob, r->kills.length ());
+	  for (auto kill : r->kills)
+	    kill.stream_out (ob);
 
 	  struct bitpack_d bp = bitpack_create (ob->main_stream);
 	  bp_pack_value (&bp, r->writes_errno, 1);
@@ -3723,6 +3705,20 @@ read_section (struct lto_file_decl_data *file_data, const char *data,
       read_modref_records (&ib, data_in,
 			   modref_sum ? &modref_sum->stores : NULL,
 			   modref_sum_lto ? &modref_sum_lto->stores : NULL);
+      int j = streamer_read_uhwi (&ib);
+      if (j && modref_sum)
+	modref_sum->kills.reserve_exact (j);
+      if (j && modref_sum_lto)
+	modref_sum_lto->kills.reserve_exact (j);
+      for (int k = 0; k < j; k++)
+	{
+	  modref_access_node a = modref_access_node::stream_in (&ib);
+
+	  if (modref_sum)
+	    modref_sum->kills.quick_push (a);
+	  if (modref_sum_lto)
+	    modref_sum_lto->kills.quick_push (a);
+	}
       struct bitpack_d bp = streamer_read_bitpack (&ib);
       if (bp_unpack_value (&bp, 1))
 	{
@@ -3863,6 +3859,27 @@ remap_arg_flags (auto_vec <eaf_flags_t> &arg_flags, clone_info *info)
     }
 }
 
+/* Update kills accrdoing to the parm map MAP.  */
+
+static void
+remap_kills (vec <modref_access_node> &kills, const vec <int> &map)
+{
+  for (size_t i = 0; i < kills.length ();)
+    if (kills[i].parm_index >= 0)
+      {
+	if (kills[i].parm_index < (int)map.length ()
+	    && map[kills[i].parm_index] != MODREF_UNKNOWN_PARM)
+	  {
+	    kills[i].parm_index = map[kills[i].parm_index];
+	    i++;
+	  }
+	else
+	  kills.unordered_remove (i);
+      }
+    else
+      i++;
+}
+
 /* If signature changed, update the summary.  */
 
 static void
@@ -3913,8 +3930,7 @@ update_signature (struct cgraph_node *node)
     {
       r->loads->remap_params (&map);
       r->stores->remap_params (&map);
-      /* TODO: One we do IPA kills analysis, update the table here.  */
-      r->kills.release ();
+      remap_kills (r->kills, map);
       if (r->arg_flags.length ())
 	remap_arg_flags (r->arg_flags, info);
     }
@@ -3922,8 +3938,7 @@ update_signature (struct cgraph_node *node)
     {
       r_lto->loads->remap_params (&map);
       r_lto->stores->remap_params (&map);
-      /* TODO: One we do IPA kills analysis, update the table here.  */
-      r_lto->kills.release ();
+      remap_kills (r_lto->kills, map);
       if (r_lto->arg_flags.length ())
 	remap_arg_flags (r_lto->arg_flags, info);
     }


More information about the Gcc-patches mailing list