aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/ipa-cp.cc8
-rw-r--r--gcc/ipa-modref.cc61
-rw-r--r--gcc/ipa-prop.cc17
-rw-r--r--gcc/ipa-prop.h4
-rw-r--r--gcc/testsuite/gcc.dg/lto/pr111157_0.c24
-rw-r--r--gcc/testsuite/gcc.dg/lto/pr111157_1.c10
6 files changed, 118 insertions, 6 deletions
diff --git a/gcc/ipa-cp.cc b/gcc/ipa-cp.cc
index e056030..788157e 100644
--- a/gcc/ipa-cp.cc
+++ b/gcc/ipa-cp.cc
@@ -1271,6 +1271,8 @@ ipa_argagg_value_list::dump (FILE *f)
print_generic_expr (f, av.value);
if (av.by_ref)
fprintf (f, "(by_ref)");
+ if (av.killed)
+ fprintf (f, "(killed)");
comma = true;
}
fprintf (f, "\n");
@@ -1437,6 +1439,8 @@ ipa_argagg_value_list::push_adjusted_values (unsigned src_index,
new_av.unit_offset = av->unit_offset - unit_delta;
new_av.index = dest_index;
new_av.by_ref = av->by_ref;
+ gcc_assert (!av->killed);
+ new_av.killed = false;
/* Quick check that the offsets we push are indeed increasing. */
gcc_assert (first
@@ -1473,6 +1477,7 @@ push_agg_values_from_plats (ipcp_param_lattices *plats, int dest_index,
iav.unit_offset = aglat->offset / BITS_PER_UNIT - unit_delta;
iav.index = dest_index;
iav.by_ref = plats->aggs_by_ref;
+ iav.killed = false;
gcc_assert (first
|| iav.unit_offset > prev_unit_offset);
@@ -2139,6 +2144,7 @@ ipa_push_agg_values_from_jfunc (ipa_node_params *info, cgraph_node *node,
iav.unit_offset = item.offset / BITS_PER_UNIT;
iav.index = dst_index;
iav.by_ref = agg_jfunc->by_ref;
+ iav.killed = 0;
gcc_assert (first
|| iav.unit_offset > prev_unit_offset);
@@ -3981,6 +3987,7 @@ estimate_local_effects (struct cgraph_node *node)
avals.m_known_aggs[j].unit_offset = unit_offset;
avals.m_known_aggs[j].index = index;
avals.m_known_aggs[j].by_ref = plats->aggs_by_ref;
+ avals.m_known_aggs[j].killed = false;
perform_estimation_of_a_value (node, &avals,
removable_params_cost, 0, val);
@@ -5857,6 +5864,7 @@ push_agg_values_for_index_from_edge (struct cgraph_edge *cs, int index,
iav.unit_offset = agg_jf.offset / BITS_PER_UNIT;
iav.index = index;
iav.by_ref = jfunc->agg.by_ref;
+ iav.killed = false;
gcc_assert (first
|| iav.unit_offset > prev_unit_offset);
diff --git a/gcc/ipa-modref.cc b/gcc/ipa-modref.cc
index fe55621..cbe788a 100644
--- a/gcc/ipa-modref.cc
+++ b/gcc/ipa-modref.cc
@@ -4065,21 +4065,74 @@ remap_kills (vec <modref_access_node> &kills, const vec <int> &map)
i++;
}
+/* Return true if the V can overlap with KILL. */
+
+static bool
+ipcp_argagg_and_kill_overlap_p (const ipa_argagg_value &v,
+ const modref_access_node &kill)
+{
+ if (kill.parm_index == v.index)
+ {
+ gcc_assert (kill.parm_offset_known);
+ gcc_assert (known_eq (kill.max_size, kill.size));
+ 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
+ = (kill.parm_offset << LOG2_BITS_PER_UNIT) + kill.offset;
+ if (ranges_maybe_overlap_p (repl_offset, repl_size,
+ combined_offset, kill.size))
+ return true;
+ }
+ return false;
+}
+
/* If signature changed, update the summary. */
static void
update_signature (struct cgraph_node *node)
{
- clone_info *info = clone_info::get (node);
- if (!info || !info->param_adjustments)
- return;
-
modref_summary *r = optimization_summaries
? optimization_summaries->get (node) : NULL;
modref_summary_lto *r_lto = summaries_lto
? summaries_lto->get (node) : NULL;
if (!r && !r_lto)
return;
+
+ /* Propagating constants in killed memory can lead to eliminated stores in
+ both callees (because they are considered redundant) and callers, leading
+ to missing them altogether. */
+ ipcp_transformation *ipcp_ts = ipcp_get_transformation_summary (node);
+ if (ipcp_ts)
+ {
+ for (auto &v : ipcp_ts->m_agg_values)
+ {
+ if (!v.by_ref)
+ continue;
+ if (r)
+ for (const modref_access_node &kill : r->kills)
+ if (ipcp_argagg_and_kill_overlap_p (v, kill))
+ {
+ 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))
+ {
+ v.killed = true;
+ break;
+ }
+ }
+ }
+
+ clone_info *info = clone_info::get (node);
+ if (!info || !info->param_adjustments)
+ return;
+
if (dump_file)
{
fprintf (dump_file, "Updating summary for %s from:\n",
diff --git a/gcc/ipa-prop.cc b/gcc/ipa-prop.cc
index 9442cdd..827bdb6 100644
--- a/gcc/ipa-prop.cc
+++ b/gcc/ipa-prop.cc
@@ -5299,6 +5299,7 @@ write_ipcp_transformation_info (output_block *ob, cgraph_node *node,
bp = bitpack_create (ob->main_stream);
bp_pack_value (&bp, av.by_ref, 1);
+ bp_pack_value (&bp, av.killed, 1);
streamer_write_bitpack (&bp);
}
@@ -5331,6 +5332,7 @@ read_ipcp_transformation_info (lto_input_block *ib, cgraph_node *node,
bitpack_d bp = streamer_read_bitpack (ib);
av->by_ref = bp_unpack_value (&bp, 1);
+ av->killed = bp_unpack_value (&bp, 1);
}
}
@@ -5616,7 +5618,9 @@ ipcp_modif_dom_walker::before_dom_children (basic_block bb)
/* If IPA-CP discovered a constant in parameter PARM at OFFSET of a given SIZE
- whether passed by reference or not is given by BY_REF - return that
- constant. Otherwise return NULL_TREE. */
+ constant. Otherwise return NULL_TREE. The is supposed to be used only
+ after clone materialization and transformation is done (because it asserts
+ that killed constants have been pruned). */
tree
ipcp_get_aggregate_const (struct function *func, tree parm, bool by_ref,
@@ -5634,7 +5638,11 @@ ipcp_get_aggregate_const (struct function *func, tree parm, bool by_ref,
ipa_argagg_value_list avl (ts);
unsigned unit_offset = bit_offset / BITS_PER_UNIT;
- tree v = avl.get_value (index, unit_offset, by_ref);
+ const ipa_argagg_value *av = avl.get_elt (index, unit_offset);
+ if (!av || av->by_ref != by_ref)
+ return NULL_TREE;
+ gcc_assert (!av->killed);
+ tree v = av->value;
if (!v
|| maybe_ne (tree_to_poly_int64 (TYPE_SIZE (TREE_TYPE (v))), bit_size))
return NULL_TREE;
@@ -5884,6 +5892,11 @@ ipcp_transform_function (struct cgraph_node *node)
free_ipa_bb_info (bi);
fbi.bb_infos.release ();
+ ts->remove_argaggs_if ([](const ipa_argagg_value &v)
+ {
+ return v.killed;
+ });
+
vec_free (descriptors);
if (cfg_changed)
delete_unreachable_blocks_update_callgraph (node, false);
diff --git a/gcc/ipa-prop.h b/gcc/ipa-prop.h
index 34b0d77..fcd0e5c 100644
--- a/gcc/ipa-prop.h
+++ b/gcc/ipa-prop.h
@@ -213,6 +213,10 @@ struct GTY(()) ipa_argagg_value
unsigned index : IPA_PROP_ARG_INDEX_LIMIT_BITS;
/* Whether the value was passed by reference. */
unsigned by_ref : 1;
+ /* Set if the value should not be used after materialization in
+ value_numbering. It is kept around just so that clone materialization can
+ distinguish a combined IPA-CP and IPA-SRA from a deleted argument. */
+ unsigned killed : 1;
};
/* A view into a sorted list of aggregate values in a particular context, be it
diff --git a/gcc/testsuite/gcc.dg/lto/pr111157_0.c b/gcc/testsuite/gcc.dg/lto/pr111157_0.c
new file mode 100644
index 0000000..8bb4c65
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/lto/pr111157_0.c
@@ -0,0 +1,24 @@
+/* { dg-lto-do run } */
+/* { dg-lto-options { { -O2 -flto=auto } } } */
+/* { dg-extra-ld-options { -flto-partition=1to1 } } */
+
+extern __attribute__((noinline))
+void foo (int *p);
+
+
+void __attribute__((noinline))
+bar (void)
+{
+ int istat;
+
+ istat = 1234;
+ foo (&istat);
+ if (istat != 1234)
+ __builtin_abort ();
+}
+
+int main (int argc, char **argv)
+{
+ bar ();
+ return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/lto/pr111157_1.c b/gcc/testsuite/gcc.dg/lto/pr111157_1.c
new file mode 100644
index 0000000..f9ba5af
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/lto/pr111157_1.c
@@ -0,0 +1,10 @@
+volatile int v = 0;
+
+void __attribute__((noinline))
+foo (int *p)
+{
+ *p = 1234;
+ if (v)
+ *p = 0;
+ return;
+}