diff mbox series

[3/3] ipa: Limit pruning of IPA-CP aggregate constants if there are loads

Message ID dce484200c834821ecf57f8fe1b4610e8e64b841.1696508299.git.mjambor@suse.cz
State New
Headers show
Series [1/3] ipa-cp: Templatize filtering of m_agg_values | expand

Commit Message

Martin Jambor Oct. 5, 2023, 12:06 p.m. UTC
This patch makes the previous one less conservative by looking whether
there are known ipa-modref loads from areas covered by the IPA-CP
aggregate constant entry in question.  Because ipa-modref relies on
alias information which IPA-CP does not have (yet), the test is much
more crude and only reports overlapping accesses with known offsets
and max_size.

I was not able to put together a testcase which would fail without
this patch however.  It basically needs to be a combination of
testcases for PR 92497 (so that IPA-CP transformation phase is not
enough), PR 111157 (to get a load) and PR 103669 (to get a
clobber/kill) in a way that ipa-modref can still track things.
Therefore I am not sure if we actually want this patch.

gcc/ChangeLog:

2023-10-04  Martin Jambor  <mjambor@suse.cz>

	* ipa-modref.cc (ipcp_argagg_and_access_must_overlap_p): New function.
	(ipcp_argagg_and_modref_tree_must_overlap_p): Likewise.
	(update_signature): Use ipcp_argagg_and_modref_tree_must_overlap_p.

Combined third step
---
 gcc/ipa-modref.cc | 65 +++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 63 insertions(+), 2 deletions(-)
diff mbox series

Patch

diff --git a/gcc/ipa-modref.cc b/gcc/ipa-modref.cc
index a8fcf159259..d2bfca3445d 100644
--- a/gcc/ipa-modref.cc
+++ b/gcc/ipa-modref.cc
@@ -4090,6 +4090,64 @@  ipcp_argagg_and_kill_overlap_p (const ipa_argagg_value &v,
   return false;
 }
 
+/* Return true if V overlaps with ACCESS_NODE.  When in doubt, return
+   false.  */
+
+static bool
+ipcp_argagg_and_access_must_overlap_p (const ipa_argagg_value &v,
+				       const modref_access_node &access_node)
+{
+  if (access_node.parm_index == MODREF_GLOBAL_MEMORY_PARM
+      || access_node.parm_index == MODREF_UNKNOWN_PARM
+      || access_node.parm_index == MODREF_GLOBAL_MEMORY_PARM)
+      return false;
+
+  if (access_node.parm_index == v.index)
+    {
+      if (!access_node.parm_offset_known)
+	return false;
+
+      poly_int64 repl_size;
+      bool ok = poly_int_tree_p (TYPE_SIZE (TREE_TYPE (v.value)),
+				 &repl_size);
+      gcc_assert (ok);
+      poly_int64 repl_offset (v.unit_offset);
+      repl_offset <<= LOG2_BITS_PER_UNIT;
+      poly_int64 combined_offset
+	= (access_node.parm_offset << LOG2_BITS_PER_UNIT) + access_node.offset;
+      if (ranges_maybe_overlap_p (repl_offset, repl_size,
+				  combined_offset, access_node.max_size))
+	return true;
+    }
+  return false;
+}
+
+/* Return true if MT contains an access that certainly overlaps with V even
+   when we cannot evaluate alias references.  When in doubt, return false.  */
+
+template <typename base>
+static bool
+ipcp_argagg_and_modref_tree_must_overlap_p (const ipa_argagg_value &v,
+					    const modref_tree<base> &mt)
+{
+  for (auto base_node : mt.bases)
+    {
+      if (base_node->every_ref)
+	return false;
+      for (auto ref_node : base_node->refs)
+	{
+	  if (ref_node->every_access)
+	    return false;
+	  for (auto access_node : ref_node->accesses)
+	    {
+	      if (ipcp_argagg_and_access_must_overlap_p (v, access_node))
+		return true;
+	    }
+	}
+    }
+  return false;
+}
+
 /* If signature changed, update the summary.  */
 
 static void
@@ -4111,14 +4169,17 @@  update_signature (struct cgraph_node *node)
 	  continue;
 	if (r)
 	  for (const modref_access_node &kill : r->kills)
-	    if (ipcp_argagg_and_kill_overlap_p (v, kill))
+	    if (ipcp_argagg_and_kill_overlap_p (v, kill)
+		&& !ipcp_argagg_and_modref_tree_must_overlap_p (v, *r->loads))
 	      {
 		v.killed = true;
 		break;
 	      }
 	if (!v.killed && r_lto)
 	  for (const modref_access_node &kill : r_lto->kills)
-	    if (ipcp_argagg_and_kill_overlap_p (v, kill))
+	    if (ipcp_argagg_and_kill_overlap_p (v, kill)
+		&& !ipcp_argagg_and_modref_tree_must_overlap_p (v,
+								*r_lto->loads))
 	      {
 		v.killed = 1;
 		break;