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 <mjam...@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 --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; -- 2.42.0