aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJan Hubicka <jh@suse.cz>2021-11-17 20:40:44 +0100
committerJan Hubicka <jh@suse.cz>2021-11-17 20:40:44 +0100
commit74509b963ef64101ce601a497913c13021994f51 (patch)
tree11a9e8c4d19a6e7b31959b1b5ce8fd1ed58056fa
parentef342b2d99e7947a15e72ed02173d235feaf35f0 (diff)
downloadgcc-74509b963ef64101ce601a497913c13021994f51.zip
gcc-74509b963ef64101ce601a497913c13021994f51.tar.gz
gcc-74509b963ef64101ce601a497913c13021994f51.tar.bz2
Add very basic IPA part of modref-kill analysis
gcc/ChangeLog: 2021-11-17 Jan Hubicka <hubicka@ucw.cz> * ipa-modref-tree.c: Include cgraph.h and tree-streamer.h. (modref_access_node::stream_out): New member function. (modref_access_node::stream_in): New member function. * ipa-modref-tree.h (modref_access_node::stream_out, modref_access_node::stream_in): Declare. * ipa-modref.c (modref_summary_lto::useful_p): Free useless kills. (modref_summary_lto::dump): Dump kills. (analyze_store): Record kills for LTO (analyze_stmt): Likewise. (modref_summaries_lto::duplicate): Duplicate kills. (write_modref_records): Use new stream_out member function. (read_modref_records): Likewise. (modref_write): Stream out kills. (read_section): Stream in kills (remap_kills): New function. (update_signature): Use it.
-rw-r--r--gcc/ipa-modref-tree.c46
-rw-r--r--gcc/ipa-modref-tree.h4
-rw-r--r--gcc/ipa-modref.c121
3 files changed, 118 insertions, 53 deletions
diff --git a/gcc/ipa-modref-tree.c b/gcc/ipa-modref-tree.c
index bbe23a5..e23d88d 100644
--- a/gcc/ipa-modref-tree.c
+++ b/gcc/ipa-modref-tree.c
@@ -27,6 +27,8 @@ along with GCC; see the file COPYING3. If not see
#include "selftest.h"
#include "tree-ssa-alias.h"
#include "gimple.h"
+#include "cgraph.h"
+#include "tree-streamer.h"
/* Return true if both accesses are the same. */
bool
@@ -458,6 +460,50 @@ modref_access_node::try_merge_with (vec <modref_access_node, va_gc> *&accesses,
i++;
}
+/* Stream out to OB. */
+
+void
+modref_access_node::stream_out (struct output_block *ob) const
+{
+ streamer_write_hwi (ob, parm_index);
+ if (parm_index != MODREF_UNKNOWN_PARM)
+ {
+ streamer_write_uhwi (ob, parm_offset_known);
+ if (parm_offset_known)
+ {
+ streamer_write_poly_int64 (ob, parm_offset);
+ streamer_write_poly_int64 (ob, offset);
+ streamer_write_poly_int64 (ob, size);
+ streamer_write_poly_int64 (ob, max_size);
+ }
+ }
+}
+
+modref_access_node
+modref_access_node::stream_in (struct lto_input_block *ib)
+{
+ int parm_index = streamer_read_hwi (ib);
+ bool parm_offset_known = false;
+ poly_int64 parm_offset = 0;
+ poly_int64 offset = 0;
+ poly_int64 size = -1;
+ poly_int64 max_size = -1;
+
+ if (parm_index != MODREF_UNKNOWN_PARM)
+ {
+ parm_offset_known = streamer_read_uhwi (ib);
+ if (parm_offset_known)
+ {
+ parm_offset = streamer_read_poly_int64 (ib);
+ offset = streamer_read_poly_int64 (ib);
+ size = streamer_read_poly_int64 (ib);
+ max_size = streamer_read_poly_int64 (ib);
+ }
+ }
+ return {offset, size, max_size, parm_offset, parm_index,
+ parm_offset_known, false};
+}
+
/* Insert access with OFFSET and SIZE.
Collapse tree if it has more than MAX_ACCESSES entries.
If RECORD_ADJUSTMENTs is true avoid too many interval extensions.
diff --git a/gcc/ipa-modref-tree.h b/gcc/ipa-modref-tree.h
index 1bf2aa8..0a09734 100644
--- a/gcc/ipa-modref-tree.h
+++ b/gcc/ipa-modref-tree.h
@@ -99,6 +99,10 @@ struct GTY(()) modref_access_node
tree get_call_arg (const gcall *stmt) const;
/* Build ao_ref corresponding to the access and return true if succesful. */
bool get_ao_ref (const gcall *stmt, class ao_ref *ref) const;
+ /* Stream access to OB. */
+ void stream_out (struct output_block *ob) const;
+ /* Stream access in from IB. */
+ static modref_access_node stream_in (struct lto_input_block *ib);
/* Insert A into vector ACCESSES. Limit size of vector to MAX_ACCESSES and
if RECORD_ADJUSTMENT is true keep track of adjustment counts.
Return 0 if nothing changed, 1 is insertion suceeded and -1 if failed. */
diff --git a/gcc/ipa-modref.c b/gcc/ipa-modref.c
index 90cd1be..9ceecdd 100644
--- a/gcc/ipa-modref.c
+++ b/gcc/ipa-modref.c
@@ -410,6 +410,8 @@ modref_summary_lto::useful_p (int ecf_flags, bool check_flags)
&& (ecf_flags & ECF_LOOPING_CONST_OR_PURE));
if (loads && !loads->every_base)
return true;
+ else
+ kills.release ();
if (ecf_flags & ECF_PURE)
return ((!side_effects || !nondeterministic)
&& (ecf_flags & ECF_LOOPING_CONST_OR_PURE));
@@ -634,6 +636,15 @@ modref_summary_lto::dump (FILE *out)
dump_lto_records (loads, out);
fprintf (out, " stores:\n");
dump_lto_records (stores, out);
+ if (kills.length ())
+ {
+ fprintf (out, " kills:\n");
+ for (auto kill : kills)
+ {
+ fprintf (out, " ");
+ kill.dump (out);
+ }
+ }
if (writes_errno)
fprintf (out, " Writes errno\n");
if (side_effects)
@@ -1527,15 +1538,17 @@ analyze_store (gimple *stmt, tree, tree op, void *data)
record_access (summary->stores, &r, a);
if (summary_lto)
record_access_lto (summary_lto->stores, &r, a);
- if (summary
- && ((summary_ptrs *)data)->always_executed
+ if (((summary_ptrs *)data)->always_executed
&& a.useful_for_kill_p ()
&& (!cfun->can_throw_non_call_exceptions
|| !stmt_could_throw_p (cfun, stmt)))
{
if (dump_file)
fprintf (dump_file, " - Recording kill\n");
- modref_access_node::insert_kill (summary->kills, a, false);
+ if (summary)
+ modref_access_node::insert_kill (summary->kills, a, false);
+ if (summary_lto)
+ modref_access_node::insert_kill (summary_lto->kills, a, false);
}
return false;
}
@@ -1554,8 +1567,7 @@ analyze_stmt (modref_summary *summary, modref_summary_lto *summary_lto,
Similar logic is in ipa-pure-const.c. */
if ((ipa || cfun->after_inlining) && gimple_clobber_p (stmt))
{
- if (summary
- && always_executed && record_access_p (gimple_assign_lhs (stmt)))
+ if (always_executed && record_access_p (gimple_assign_lhs (stmt)))
{
ao_ref r;
ao_ref_init (&r, gimple_assign_lhs (stmt));
@@ -1564,7 +1576,10 @@ analyze_stmt (modref_summary *summary, modref_summary_lto *summary_lto,
{
if (dump_file)
fprintf (dump_file, " - Recording kill\n");
- modref_access_node::insert_kill (summary->kills, a, false);
+ if (summary)
+ modref_access_node::insert_kill (summary->kills, a, false);
+ if (summary_lto)
+ modref_access_node::insert_kill (summary_lto->kills, a, false);
}
}
return true;
@@ -3270,6 +3285,8 @@ modref_summaries_lto::duplicate (cgraph_node *, cgraph_node *,
src_data->loads->max_refs,
src_data->loads->max_accesses);
dst_data->loads->copy_from (src_data->loads);
+ dst_data->kills.reserve_exact (src_data->kills.length ());
+ dst_data->kills.splice (src_data->kills);
dst_data->writes_errno = src_data->writes_errno;
dst_data->side_effects = src_data->side_effects;
dst_data->nondeterministic = src_data->nondeterministic;
@@ -3324,40 +3341,21 @@ write_modref_records (modref_records_lto *tt, struct output_block *ob)
streamer_write_uhwi (ob, tt->every_base);
streamer_write_uhwi (ob, vec_safe_length (tt->bases));
- size_t i;
- modref_base_node <tree> *base_node;
- FOR_EACH_VEC_SAFE_ELT (tt->bases, i, base_node)
+ for (auto base_node : tt->bases)
{
stream_write_tree (ob, base_node->base, true);
streamer_write_uhwi (ob, base_node->every_ref);
streamer_write_uhwi (ob, vec_safe_length (base_node->refs));
- size_t j;
- modref_ref_node <tree> *ref_node;
- FOR_EACH_VEC_SAFE_ELT (base_node->refs, j, ref_node)
+ for (auto ref_node : base_node->refs)
{
stream_write_tree (ob, ref_node->ref, true);
streamer_write_uhwi (ob, ref_node->every_access);
streamer_write_uhwi (ob, vec_safe_length (ref_node->accesses));
- size_t k;
- modref_access_node *access_node;
- FOR_EACH_VEC_SAFE_ELT (ref_node->accesses, k, access_node)
- {
- streamer_write_hwi (ob, access_node->parm_index);
- if (access_node->parm_index != -1)
- {
- streamer_write_uhwi (ob, access_node->parm_offset_known);
- if (access_node->parm_offset_known)
- {
- streamer_write_poly_int64 (ob, access_node->parm_offset);
- streamer_write_poly_int64 (ob, access_node->offset);
- streamer_write_poly_int64 (ob, access_node->size);
- streamer_write_poly_int64 (ob, access_node->max_size);
- }
- }
- }
+ for (auto access_node : ref_node->accesses)
+ access_node.stream_out (ob);
}
}
}
@@ -3469,26 +3467,7 @@ read_modref_records (lto_input_block *ib, struct data_in *data_in,
for (size_t k = 0; k < naccesses; k++)
{
- int parm_index = streamer_read_hwi (ib);
- bool parm_offset_known = false;
- poly_int64 parm_offset = 0;
- poly_int64 offset = 0;
- poly_int64 size = -1;
- poly_int64 max_size = -1;
-
- if (parm_index != -1)
- {
- parm_offset_known = streamer_read_uhwi (ib);
- if (parm_offset_known)
- {
- parm_offset = streamer_read_poly_int64 (ib);
- offset = streamer_read_poly_int64 (ib);
- size = streamer_read_poly_int64 (ib);
- max_size = streamer_read_poly_int64 (ib);
- }
- }
- modref_access_node a = {offset, size, max_size, parm_offset,
- parm_index, parm_offset_known, false};
+ modref_access_node a = modref_access_node::stream_in (ib);
if (nolto_ref_node)
nolto_ref_node->insert_access (a, max_accesses, false);
if (lto_ref_node)
@@ -3599,6 +3578,9 @@ modref_write ()
write_modref_records (r->loads, ob);
write_modref_records (r->stores, ob);
+ streamer_write_uhwi (ob, r->kills.length ());
+ for (auto kill : r->kills)
+ kill.stream_out (ob);
struct bitpack_d bp = bitpack_create (ob->main_stream);
bp_pack_value (&bp, r->writes_errno, 1);
@@ -3723,6 +3705,20 @@ read_section (struct lto_file_decl_data *file_data, const char *data,
read_modref_records (&ib, data_in,
modref_sum ? &modref_sum->stores : NULL,
modref_sum_lto ? &modref_sum_lto->stores : NULL);
+ int j = streamer_read_uhwi (&ib);
+ if (j && modref_sum)
+ modref_sum->kills.reserve_exact (j);
+ if (j && modref_sum_lto)
+ modref_sum_lto->kills.reserve_exact (j);
+ for (int k = 0; k < j; k++)
+ {
+ modref_access_node a = modref_access_node::stream_in (&ib);
+
+ if (modref_sum)
+ modref_sum->kills.quick_push (a);
+ if (modref_sum_lto)
+ modref_sum_lto->kills.quick_push (a);
+ }
struct bitpack_d bp = streamer_read_bitpack (&ib);
if (bp_unpack_value (&bp, 1))
{
@@ -3863,6 +3859,27 @@ remap_arg_flags (auto_vec <eaf_flags_t> &arg_flags, clone_info *info)
}
}
+/* Update kills accrdoing to the parm map MAP. */
+
+static void
+remap_kills (vec <modref_access_node> &kills, const vec <int> &map)
+{
+ for (size_t i = 0; i < kills.length ();)
+ if (kills[i].parm_index >= 0)
+ {
+ if (kills[i].parm_index < (int)map.length ()
+ && map[kills[i].parm_index] != MODREF_UNKNOWN_PARM)
+ {
+ kills[i].parm_index = map[kills[i].parm_index];
+ i++;
+ }
+ else
+ kills.unordered_remove (i);
+ }
+ else
+ i++;
+}
+
/* If signature changed, update the summary. */
static void
@@ -3913,8 +3930,7 @@ update_signature (struct cgraph_node *node)
{
r->loads->remap_params (&map);
r->stores->remap_params (&map);
- /* TODO: One we do IPA kills analysis, update the table here. */
- r->kills.release ();
+ remap_kills (r->kills, map);
if (r->arg_flags.length ())
remap_arg_flags (r->arg_flags, info);
}
@@ -3922,8 +3938,7 @@ update_signature (struct cgraph_node *node)
{
r_lto->loads->remap_params (&map);
r_lto->stores->remap_params (&map);
- /* TODO: One we do IPA kills analysis, update the table here. */
- r_lto->kills.release ();
+ remap_kills (r_lto->kills, map);
if (r_lto->arg_flags.length ())
remap_arg_flags (r_lto->arg_flags, info);
}