On 07/09/2015 07:44 PM, Jeff Law wrote:
On 07/09/2015 03:13 AM, mliska wrote:
gcc/ChangeLog:
2015-07-03 Martin Liska <mli...@suse.cz>
* ipa-pure-const.c (struct funct_state_d): New.
(funct_state_d::default_p): Likewise.
(has_function_state): Remove.
(get_function_state): Likewise.
(set_function_state): Likewise.
(add_new_function): Rename and port to ::insert.
(duplicate_node_data): Rename and port to ::duplicate.
(funct_state_summary_t::duplicate): New function.
(register_hooks): Remove hook registration.
(pure_const_generate_summary): Use new data structure.
(pure_const_write_summary): Likewise.
(pure_const_read_summary): Likewise.
(propagate_pure_const): Likewise.
(propagate_nothrow): Likewise.
(execute): Remove hook usage.
(pass_ipa_pure_const::pass_ipa_pure_const): Likewise.
---
@@ -84,6 +85,18 @@ const char *pure_const_names[3] = {"const", "pure",
"neither"};
decl. */
struct funct_state_d
{
+ funct_state_d (): pure_const_state (IPA_NEITHER),
+ state_previously_known (IPA_NEITHER), looping_previously_known (true),
+ looping (true), can_throw (true), can_free (true) {}
+
+ funct_state_d (const funct_state_d &s): pure_const_state
(s.pure_const_state),
+ state_previously_known (s.state_previously_known),
+ looping_previously_known (s.looping_previously_known),
+ looping (s.looping), can_throw (s.can_throw), can_free (s.can_free) {}
+
+ /* Return true if the value is default. */
+ bool default_p ();
+
/* See above. */
enum pure_const_state_e pure_const_state;
/* What user set here; we can be always sure about this. */
Doesn't this need to be a "class" rather then a "struct"?
OK with that change.
jeff
Yeah.
'class' will be more appropriate. As I'm going to be AFK for Friday and
upcoming weekend,
I will install these patches on Monday.
Thanks,
Martin
>From b20c6ceaf82210c564465be1ab92f6586fc706e4 Mon Sep 17 00:00:00 2001
From: mliska <mli...@suse.cz>
Date: Thu, 9 Jul 2015 11:13:55 +0200
Subject: [PATCH 6/6] Migrate ipa-pure-const to function_summary.
gcc/ChangeLog:
2015-07-03 Martin Liska <mli...@suse.cz>
* ipa-pure-const.c (struct funct_state_d): New.
(funct_state_d::default_p): Likewise.
(has_function_state): Remove.
(get_function_state): Likewise.
(set_function_state): Likewise.
(add_new_function): Rename and port to ::insert.
(duplicate_node_data): Rename and port to ::duplicate.
(funct_state_summary_t::duplicate): New function.
(register_hooks): Remove hook registration.
(pure_const_generate_summary): Use new data structure.
(pure_const_write_summary): Likewise.
(pure_const_read_summary): Likewise.
(propagate_pure_const): Likewise.
(propagate_nothrow): Likewise.
(execute): Remove hook usage.
(pass_ipa_pure_const::pass_ipa_pure_const): Likewise.
---
gcc/ipa-pure-const.c | 180 +++++++++++++++++++--------------------------------
1 file changed, 68 insertions(+), 112 deletions(-)
diff --git a/gcc/ipa-pure-const.c b/gcc/ipa-pure-const.c
index f0373e6..f978950f 100644
--- a/gcc/ipa-pure-const.c
+++ b/gcc/ipa-pure-const.c
@@ -67,6 +67,7 @@ along with GCC; see the file COPYING3. If not see
#include "intl.h"
#include "opts.h"
#include "varasm.h"
+#include "symbol-summary.h"
/* Lattice values for const and pure functions. Everything starts out
being const, then may drop to pure and then neither depending on
@@ -82,8 +83,21 @@ const char *pure_const_names[3] = {"const", "pure", "neither"};
/* Holder for the const_state. There is one of these per function
decl. */
-struct funct_state_d
+class funct_state_d
{
+public:
+ funct_state_d (): pure_const_state (IPA_NEITHER),
+ state_previously_known (IPA_NEITHER), looping_previously_known (true),
+ looping (true), can_throw (true), can_free (true) {}
+
+ funct_state_d (const funct_state_d &s): pure_const_state (s.pure_const_state),
+ state_previously_known (s.state_previously_known),
+ looping_previously_known (s.looping_previously_known),
+ looping (s.looping), can_throw (s.can_throw), can_free (s.can_free) {}
+
+ /* Return true if the value is default. */
+ bool default_p ();
+
/* See above. */
enum pure_const_state_e pure_const_state;
/* What user set here; we can be always sure about this. */
@@ -105,10 +119,16 @@ struct funct_state_d
bool can_free;
};
-/* State used when we know nothing about function. */
-static struct funct_state_d varying_state
- = { IPA_NEITHER, IPA_NEITHER, true, true, true, true };
-
+bool
+funct_state_d::default_p ()
+{
+ return pure_const_state == IPA_NEITHER
+ && state_previously_known == IPA_NEITHER
+ && looping_previously_known
+ && looping
+ && can_throw
+ && can_free;
+}
typedef struct funct_state_d * funct_state;
@@ -116,9 +136,19 @@ typedef struct funct_state_d * funct_state;
possibility that it may be desirable to move this to the cgraph
local info. */
-/* Array, indexed by cgraph node uid, of function states. */
+class funct_state_summary_t: public function_summary <funct_state_d *>
+{
+public:
+ funct_state_summary_t (symbol_table *symtab):
+ function_summary <funct_state_d *> (symtab) {}
+
+ virtual void insert (cgraph_node *, funct_state_d *state);
+ virtual void duplicate (cgraph_node *src_node, cgraph_node *dst_node,
+ funct_state_d *src_data,
+ funct_state_d *dst_data);
+};
-static vec<funct_state> funct_state_vec;
+static funct_state_summary_t *funct_state_summaries = NULL;
static bool gate_pure_const (void);
@@ -150,12 +180,6 @@ public:
private:
bool init_p;
-
- /* Holders of ipa cgraph hooks: */
- struct cgraph_node_hook_list *function_insertion_hook_holder;
- struct cgraph_2node_hook_list *node_duplication_hook_holder;
- struct cgraph_node_hook_list *node_removal_hook_holder;
-
}; // class pass_ipa_pure_const
} // anon namespace
@@ -237,41 +261,6 @@ warn_function_noreturn (tree decl)
true, warned_about, "noreturn");
}
-/* Return true if we have a function state for NODE. */
-
-static inline bool
-has_function_state (struct cgraph_node *node)
-{
- if (!funct_state_vec.exists ()
- || funct_state_vec.length () <= (unsigned int)node->uid)
- return false;
- return funct_state_vec[node->uid] != NULL;
-}
-
-/* Return the function state from NODE. */
-
-static inline funct_state
-get_function_state (struct cgraph_node *node)
-{
- if (!funct_state_vec.exists ()
- || funct_state_vec.length () <= (unsigned int)node->uid
- || !funct_state_vec[node->uid])
- /* We might want to put correct previously_known state into varying. */
- return &varying_state;
- return funct_state_vec[node->uid];
-}
-
-/* Set the function state S for NODE. */
-
-static inline void
-set_function_state (struct cgraph_node *node, funct_state s)
-{
- if (!funct_state_vec.exists ()
- || funct_state_vec.length () <= (unsigned int)node->uid)
- funct_state_vec.safe_grow_cleared (node->uid + 1);
- funct_state_vec[node->uid] = s;
-}
-
/* Check to see if the use (or definition when CHECKING_WRITE is true)
variable T is legal in a function that is either pure or const. */
@@ -903,9 +892,8 @@ end:
return l;
}
-/* Called when new function is inserted to callgraph late. */
-static void
-add_new_function (struct cgraph_node *node, void *data ATTRIBUTE_UNUSED)
+void
+funct_state_summary_t::insert (cgraph_node *node, funct_state_d *state)
{
if (node->get_availability () < AVAIL_INTERPOSABLE)
return;
@@ -915,36 +903,21 @@ add_new_function (struct cgraph_node *node, void *data ATTRIBUTE_UNUSED)
operations. */
if (node->get_availability () > AVAIL_INTERPOSABLE
&& opt_for_fn (node->decl, flag_ipa_pure_const))
- set_function_state (node, analyze_function (node, true));
-}
-
-/* Called when new clone is inserted to callgraph late. */
-
-static void
-duplicate_node_data (struct cgraph_node *src, struct cgraph_node *dst,
- void *data ATTRIBUTE_UNUSED)
-{
- if (has_function_state (src))
{
- funct_state l = XNEW (struct funct_state_d);
- gcc_assert (!has_function_state (dst));
- memcpy (l, get_function_state (src), sizeof (*l));
- set_function_state (dst, l);
+ funct_state_d *a = analyze_function (node, true);
+ new (state) funct_state_d (*a);
+ free (a);
}
}
/* Called when new clone is inserted to callgraph late. */
-static void
-remove_node_data (struct cgraph_node *node, void *data ATTRIBUTE_UNUSED)
+void
+funct_state_summary_t::duplicate (cgraph_node *, cgraph_node *,
+ funct_state_d *src_data,
+ funct_state_d *dst_data)
{
- if (has_function_state (node))
- {
- funct_state l = get_function_state (node);
- if (l != &varying_state)
- free (l);
- set_function_state (node, NULL);
- }
+ new (dst_data) funct_state_d (*src_data);
}
@@ -957,12 +930,7 @@ register_hooks (void)
init_p = true;
- node_removal_hook_holder =
- symtab->add_cgraph_removal_hook (&remove_node_data, NULL);
- node_duplication_hook_holder =
- symtab->add_cgraph_duplication_hook (&duplicate_node_data, NULL);
- function_insertion_hook_holder =
- symtab->add_cgraph_insertion_hook (&add_new_function, NULL);
+ funct_state_summaries = new funct_state_summary_t (symtab);
}
@@ -986,7 +954,11 @@ pure_const_generate_summary (void)
FOR_EACH_DEFINED_FUNCTION (node)
if (node->get_availability () >= AVAIL_INTERPOSABLE
&& opt_for_fn (node->decl, flag_ipa_pure_const))
- set_function_state (node, analyze_function (node, true));
+ {
+ funct_state_d *a = analyze_function (node, true);
+ new (funct_state_summaries->get (node)) funct_state_d (*a);
+ free (a);
+ }
}
@@ -1008,7 +980,8 @@ pure_const_write_summary (void)
lsei_next_function_in_partition (&lsei))
{
node = lsei_cgraph_node (lsei);
- if (node->definition && has_function_state (node))
+ if (node->definition
+ && !funct_state_summaries->get (node)->default_p ())
count++;
}
@@ -1019,15 +992,13 @@ pure_const_write_summary (void)
lsei_next_function_in_partition (&lsei))
{
node = lsei_cgraph_node (lsei);
- if (node->definition && has_function_state (node))
+ funct_state_d *fs = funct_state_summaries->get (node);
+ if (node->definition && !fs->default_p ())
{
struct bitpack_d bp;
- funct_state fs;
int node_ref;
lto_symtab_encoder_t encoder;
- fs = get_function_state (node);
-
encoder = ob->decl_state->symtab_node_encoder;
node_ref = lto_symtab_encoder_encode (encoder, node);
streamer_write_uhwi_stream (ob->main_stream, node_ref);
@@ -1082,13 +1053,12 @@ pure_const_read_summary (void)
funct_state fs;
lto_symtab_encoder_t encoder;
- fs = XCNEW (struct funct_state_d);
index = streamer_read_uhwi (ib);
encoder = file_data->symtab_node_encoder;
node = dyn_cast<cgraph_node *> (lto_symtab_encoder_deref (encoder,
index));
- set_function_state (node, fs);
+ fs = funct_state_summaries->get (node);
/* Note that the flags must be read in the opposite
order in which they were written (the bitflags were
pushed into FLAGS). */
@@ -1216,7 +1186,7 @@ propagate_pure_const (void)
int i;
struct ipa_ref *ref = NULL;
- funct_state w_l = get_function_state (w);
+ funct_state w_l = funct_state_summaries->get (w);
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, " Visiting %s/%i state:%s looping %i\n",
w->name (),
@@ -1272,7 +1242,7 @@ propagate_pure_const (void)
}
if (avail > AVAIL_INTERPOSABLE)
{
- funct_state y_l = get_function_state (y);
+ funct_state_d *y_l = funct_state_summaries->get (y);
if (dump_file && (dump_flags & TDF_DETAILS))
{
fprintf (dump_file,
@@ -1389,7 +1359,7 @@ propagate_pure_const (void)
while (w && !can_free)
{
struct cgraph_edge *e;
- funct_state w_l = get_function_state (w);
+ funct_state_d *w_l = funct_state_summaries->get (w);
if (w_l->can_free
|| w->get_availability () == AVAIL_INTERPOSABLE
@@ -1403,7 +1373,7 @@ propagate_pure_const (void)
function_or_virtual_thunk_symbol (&avail);
if (avail > AVAIL_INTERPOSABLE)
- can_free = get_function_state (y)->can_free;
+ can_free = funct_state_summaries->get (y)->can_free;
else
can_free = true;
}
@@ -1416,7 +1386,7 @@ propagate_pure_const (void)
w = node;
while (w)
{
- funct_state w_l = get_function_state (w);
+ funct_state_d *w_l = funct_state_summaries->get (w);
enum pure_const_state_e this_state = pure_const_state;
bool this_looping = looping;
@@ -1526,7 +1496,7 @@ propagate_nothrow (void)
while (w && !can_throw)
{
struct cgraph_edge *e, *ie;
- funct_state w_l = get_function_state (w);
+ funct_state_d *w_l = funct_state_summaries->get (w);
if (w_l->can_throw
|| w->get_availability () == AVAIL_INTERPOSABLE)
@@ -1540,7 +1510,7 @@ propagate_nothrow (void)
if (avail > AVAIL_INTERPOSABLE)
{
- funct_state y_l = get_function_state (y);
+ funct_state_d *y_l = funct_state_summaries->get (y);
if (y_l->can_throw && !TREE_NOTHROW (w->decl)
&& e->can_throw_external)
@@ -1561,7 +1531,7 @@ propagate_nothrow (void)
w = node;
while (w)
{
- funct_state w_l = get_function_state (w);
+ funct_state_d *w_l = funct_state_summaries->get (w);
if (!can_throw && !TREE_NOTHROW (w->decl))
{
/* Inline clones share declaration with their offline copies;
@@ -1594,23 +1564,14 @@ unsigned int
pass_ipa_pure_const::
execute (function *)
{
- struct cgraph_node *node;
bool remove_p;
- symtab->remove_cgraph_insertion_hook (function_insertion_hook_holder);
- symtab->remove_cgraph_duplication_hook (node_duplication_hook_holder);
- symtab->remove_cgraph_removal_hook (node_removal_hook_holder);
-
/* Nothrow makes more function to not lead to return and improve
later analysis. */
propagate_nothrow ();
remove_p = propagate_pure_const ();
- /* Cleanup. */
- FOR_EACH_FUNCTION (node)
- if (has_function_state (node))
- free (get_function_state (node));
- funct_state_vec.release ();
+ delete funct_state_summaries;
return remove_p ? TODO_remove_functions : 0;
}
@@ -1631,12 +1592,7 @@ pass_ipa_pure_const::pass_ipa_pure_const(gcc::context *ctxt)
0, /* function_transform_todo_flags_start */
NULL, /* function_transform */
NULL), /* variable_transform */
- init_p(false),
- function_insertion_hook_holder(NULL),
- node_duplication_hook_holder(NULL),
- node_removal_hook_holder(NULL)
-{
-}
+ init_p (false) {}
ipa_opt_pass_d *
make_pass_ipa_pure_const (gcc::context *ctxt)
--
2.4.5