@@ -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;