[3/3] ipa: Limit pruning of IPA-CP aggregate constants if there are loads
Checks
Commit Message
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(-)
@@ -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;