Commit 36330f82 by Martin Liska Committed by Martin Liska

Covert ipa-pure-const.c to symbol_summary.

2018-06-08  Martin Liska  <mliska@suse.cz>

	* ipa-pure-const.c (struct funct_state_d): Do it class instead
	of struct.
	(class funct_state_summary_t): New function_summary class.
	(has_function_state): Remove.
	(get_function_state): Likewise.
	(set_function_state): Likewise.
	(add_new_function): Likewise.
	(funct_state_summary_t::insert): New function.
	(duplicate_node_data): Remove.
	(remove_node_data): Remove.
	(funct_state_summary_t::duplicate): New function.
	(register_hooks): Create new funct_state_summaries.
	(pure_const_generate_summary): Use it.
	(pure_const_write_summary): Likewise.
	(pure_const_read_summary): Likewise.
	(propagate_pure_const): Likewise.
	(propagate_nothrow): Likewise.
	(dump_malloc_lattice): Likewise.
	(propagate_malloc): Likewise.
	(execute): Do not register hooks, just remove summary
	instead.
	(pass_ipa_pure_const::pass_ipa_pure_const): Simplify
	constructor.

From-SVN: r261313
parent 6adcb793
2018-06-08 Martin Liska <mliska@suse.cz> 2018-06-08 Martin Liska <mliska@suse.cz>
* ipa-pure-const.c (struct funct_state_d): Do it class instead
of struct.
(class funct_state_summary_t): New function_summary class.
(has_function_state): Remove.
(get_function_state): Likewise.
(set_function_state): Likewise.
(add_new_function): Likewise.
(funct_state_summary_t::insert): New function.
(duplicate_node_data): Remove.
(remove_node_data): Remove.
(funct_state_summary_t::duplicate): New function.
(register_hooks): Create new funct_state_summaries.
(pure_const_generate_summary): Use it.
(pure_const_write_summary): Likewise.
(pure_const_read_summary): Likewise.
(propagate_pure_const): Likewise.
(propagate_nothrow): Likewise.
(dump_malloc_lattice): Likewise.
(propagate_malloc): Likewise.
(execute): Do not register hooks, just remove summary
instead.
(pass_ipa_pure_const::pass_ipa_pure_const): Simplify
constructor.
2018-06-08 Martin Liska <mliska@suse.cz>
* ipa-reference.c (remove_node_data): Remove. * ipa-reference.c (remove_node_data): Remove.
(duplicate_node_data): Likewise. (duplicate_node_data): Likewise.
(class ipa_ref_var_info_summary_t): New class. (class ipa_ref_var_info_summary_t): New class.
......
...@@ -85,8 +85,20 @@ static const char *malloc_state_names[] = {"malloc_top", "malloc", "malloc_botto ...@@ -85,8 +85,20 @@ static const char *malloc_state_names[] = {"malloc_top", "malloc", "malloc_botto
/* Holder for the const_state. There is one of these per function /* Holder for the const_state. There is one of these per function
decl. */ 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),
malloc_state (STATE_MALLOC_BOTTOM) {}
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),
malloc_state (s.malloc_state) {}
/* See above. */ /* See above. */
enum pure_const_state_e pure_const_state; enum pure_const_state_e pure_const_state;
/* What user set here; we can be always sure about this. */ /* What user set here; we can be always sure about this. */
...@@ -110,20 +122,25 @@ struct funct_state_d ...@@ -110,20 +122,25 @@ struct funct_state_d
enum malloc_state_e malloc_state; enum malloc_state_e malloc_state;
}; };
/* State used when we know nothing about function. */
static struct funct_state_d varying_state
= { IPA_NEITHER, IPA_NEITHER, true, true, true, true, STATE_MALLOC_BOTTOM };
typedef struct funct_state_d * funct_state; typedef struct funct_state_d * funct_state;
/* The storage of the funct_state is abstracted because there is the /* The storage of the funct_state is abstracted because there is the
possibility that it may be desirable to move this to the cgraph possibility that it may be desirable to move this to the cgraph
local info. */ 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); static bool gate_pure_const (void);
...@@ -155,12 +172,6 @@ public: ...@@ -155,12 +172,6 @@ public:
private: private:
bool init_p; 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 }; // class pass_ipa_pure_const
} // anon namespace } // anon namespace
...@@ -278,48 +289,6 @@ warn_function_cold (tree decl) ...@@ -278,48 +289,6 @@ warn_function_cold (tree decl)
true, warned_about, "cold"); true, warned_about, "cold");
} }
/* 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);
/* If funct_state_vec already contains a funct_state, we have to release
it before it's going to be ovewritten. */
if (funct_state_vec[node->uid] != NULL
&& funct_state_vec[node->uid] != &varying_state)
free (funct_state_vec[node->uid]);
funct_state_vec[node->uid] = s;
}
/* Check to see if the use (or definition when CHECKING_WRITE is true) /* 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. */ variable T is legal in a function that is either pure or const. */
...@@ -1148,40 +1117,29 @@ end: ...@@ -1148,40 +1117,29 @@ end:
return l; return l;
} }
/* Called when new function is inserted to callgraph late. */ void
static void funct_state_summary_t::insert (cgraph_node *node, funct_state_d *state)
add_new_function (struct cgraph_node *node, void *data ATTRIBUTE_UNUSED)
{ {
/* There are some shared nodes, in particular the initializers on /* There are some shared nodes, in particular the initializers on
static declarations. We do not need to scan them more than once static declarations. We do not need to scan them more than once
since all we would be interested in are the addressof since all we would be interested in are the addressof
operations. */ operations. */
if (opt_for_fn (node->decl, flag_ipa_pure_const)) if (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); funct_state_d *a = analyze_function (node, true);
gcc_assert (!has_function_state (dst)); new (state) funct_state_d (*a);
memcpy (l, get_function_state (src), sizeof (*l)); free (a);
set_function_state (dst, l);
} }
} }
/* Called when new clone is inserted to callgraph late. */ /* Called when new clone is inserted to callgraph late. */
static void void
remove_node_data (struct cgraph_node *node, void *data ATTRIBUTE_UNUSED) funct_state_summary_t::duplicate (cgraph_node *, cgraph_node *,
funct_state_d *src_data,
funct_state_d *dst_data)
{ {
if (has_function_state (node)) new (dst_data) funct_state_d (*src_data);
set_function_state (node, NULL);
} }
...@@ -1194,12 +1152,7 @@ register_hooks (void) ...@@ -1194,12 +1152,7 @@ register_hooks (void)
init_p = true; init_p = true;
node_removal_hook_holder = funct_state_summaries = new funct_state_summary_t (symtab);
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);
} }
...@@ -1222,7 +1175,11 @@ pure_const_generate_summary (void) ...@@ -1222,7 +1175,11 @@ pure_const_generate_summary (void)
FOR_EACH_DEFINED_FUNCTION (node) FOR_EACH_DEFINED_FUNCTION (node)
if (opt_for_fn (node->decl, flag_ipa_pure_const)) if (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_create (node)) funct_state_d (*a);
free (a);
}
} }
...@@ -1244,7 +1201,7 @@ pure_const_write_summary (void) ...@@ -1244,7 +1201,7 @@ pure_const_write_summary (void)
lsei_next_function_in_partition (&lsei)) lsei_next_function_in_partition (&lsei))
{ {
node = lsei_cgraph_node (lsei); node = lsei_cgraph_node (lsei);
if (node->definition && has_function_state (node)) if (node->definition && funct_state_summaries->exists (node))
count++; count++;
} }
...@@ -1255,15 +1212,13 @@ pure_const_write_summary (void) ...@@ -1255,15 +1212,13 @@ pure_const_write_summary (void)
lsei_next_function_in_partition (&lsei)) lsei_next_function_in_partition (&lsei))
{ {
node = lsei_cgraph_node (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 != NULL)
{ {
struct bitpack_d bp; struct bitpack_d bp;
funct_state fs;
int node_ref; int node_ref;
lto_symtab_encoder_t encoder; lto_symtab_encoder_t encoder;
fs = get_function_state (node);
encoder = ob->decl_state->symtab_node_encoder; encoder = ob->decl_state->symtab_node_encoder;
node_ref = lto_symtab_encoder_encode (encoder, node); node_ref = lto_symtab_encoder_encode (encoder, node);
streamer_write_uhwi_stream (ob->main_stream, node_ref); streamer_write_uhwi_stream (ob->main_stream, node_ref);
...@@ -1319,13 +1274,12 @@ pure_const_read_summary (void) ...@@ -1319,13 +1274,12 @@ pure_const_read_summary (void)
funct_state fs; funct_state fs;
lto_symtab_encoder_t encoder; lto_symtab_encoder_t encoder;
fs = XCNEW (struct funct_state_d);
index = streamer_read_uhwi (ib); index = streamer_read_uhwi (ib);
encoder = file_data->symtab_node_encoder; encoder = file_data->symtab_node_encoder;
node = dyn_cast<cgraph_node *> (lto_symtab_encoder_deref (encoder, node = dyn_cast<cgraph_node *> (lto_symtab_encoder_deref (encoder,
index)); index));
set_function_state (node, fs);
fs = funct_state_summaries->get_create (node);
/* Note that the flags must be read in the opposite /* Note that the flags must be read in the opposite
order in which they were written (the bitflags were order in which they were written (the bitflags were
pushed into FLAGS). */ pushed into FLAGS). */
...@@ -1481,7 +1435,7 @@ propagate_pure_const (void) ...@@ -1481,7 +1435,7 @@ propagate_pure_const (void)
int i; int i;
struct ipa_ref *ref = NULL; struct ipa_ref *ref = NULL;
funct_state w_l = get_function_state (w); funct_state w_l = funct_state_summaries->get_create (w);
if (dump_file && (dump_flags & TDF_DETAILS)) if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, " Visiting %s state:%s looping %i\n", fprintf (dump_file, " Visiting %s state:%s looping %i\n",
w->dump_name (), w->dump_name (),
...@@ -1523,7 +1477,7 @@ propagate_pure_const (void) ...@@ -1523,7 +1477,7 @@ propagate_pure_const (void)
} }
if (avail > AVAIL_INTERPOSABLE) if (avail > AVAIL_INTERPOSABLE)
{ {
funct_state y_l = get_function_state (y); funct_state y_l = funct_state_summaries->get_create (y);
if (dump_file && (dump_flags & TDF_DETAILS)) if (dump_file && (dump_flags & TDF_DETAILS))
{ {
fprintf (dump_file, fprintf (dump_file,
...@@ -1637,7 +1591,7 @@ propagate_pure_const (void) ...@@ -1637,7 +1591,7 @@ propagate_pure_const (void)
while (w && !can_free) while (w && !can_free)
{ {
struct cgraph_edge *e; struct cgraph_edge *e;
funct_state w_l = get_function_state (w); funct_state w_l = funct_state_summaries->get_create (w);
if (w_l->can_free if (w_l->can_free
|| w->get_availability () == AVAIL_INTERPOSABLE || w->get_availability () == AVAIL_INTERPOSABLE
...@@ -1652,7 +1606,7 @@ propagate_pure_const (void) ...@@ -1652,7 +1606,7 @@ propagate_pure_const (void)
e->caller); e->caller);
if (avail > AVAIL_INTERPOSABLE) if (avail > AVAIL_INTERPOSABLE)
can_free = get_function_state (y)->can_free; can_free = funct_state_summaries->get_create (y)->can_free;
else else
can_free = true; can_free = true;
} }
...@@ -1665,7 +1619,7 @@ propagate_pure_const (void) ...@@ -1665,7 +1619,7 @@ propagate_pure_const (void)
w = node; w = node;
while (w) while (w)
{ {
funct_state w_l = get_function_state (w); funct_state w_l = funct_state_summaries->get_create (w);
enum pure_const_state_e this_state = pure_const_state; enum pure_const_state_e this_state = pure_const_state;
bool this_looping = looping; bool this_looping = looping;
...@@ -1804,7 +1758,7 @@ propagate_nothrow (void) ...@@ -1804,7 +1758,7 @@ propagate_nothrow (void)
if (!TREE_NOTHROW (w->decl)) if (!TREE_NOTHROW (w->decl))
{ {
funct_state w_l = get_function_state (w); funct_state w_l = funct_state_summaries->get_create (w);
if (w_l->can_throw if (w_l->can_throw
|| w->get_availability () == AVAIL_INTERPOSABLE) || w->get_availability () == AVAIL_INTERPOSABLE)
...@@ -1829,7 +1783,7 @@ propagate_nothrow (void) ...@@ -1829,7 +1783,7 @@ propagate_nothrow (void)
throw. */ throw. */
if (avail <= AVAIL_INTERPOSABLE if (avail <= AVAIL_INTERPOSABLE
|| (!TREE_NOTHROW (y->decl) || (!TREE_NOTHROW (y->decl)
&& (get_function_state (y)->can_throw && (funct_state_summaries->get_create (y)->can_throw
|| (opt_for_fn (y->decl, flag_non_call_exceptions) || (opt_for_fn (y->decl, flag_non_call_exceptions)
&& !e->callee->binds_to_current_def_p (w))))) && !e->callee->binds_to_current_def_p (w)))))
can_throw = true; can_throw = true;
...@@ -1849,7 +1803,7 @@ propagate_nothrow (void) ...@@ -1849,7 +1803,7 @@ propagate_nothrow (void)
w = node; w = node;
while (w) while (w)
{ {
funct_state w_l = get_function_state (w); funct_state w_l = funct_state_summaries->get_create (w);
if (!can_throw && !TREE_NOTHROW (w->decl)) if (!can_throw && !TREE_NOTHROW (w->decl))
{ {
/* Inline clones share declaration with their offline copies; /* Inline clones share declaration with their offline copies;
...@@ -1887,7 +1841,7 @@ dump_malloc_lattice (FILE *dump_file, const char *s) ...@@ -1887,7 +1841,7 @@ dump_malloc_lattice (FILE *dump_file, const char *s)
cgraph_node *node; cgraph_node *node;
FOR_EACH_FUNCTION (node) FOR_EACH_FUNCTION (node)
{ {
funct_state fs = get_function_state (node); funct_state fs = funct_state_summaries->get_create (node);
malloc_state_e state = fs->malloc_state; malloc_state_e state = fs->malloc_state;
fprintf (dump_file, "%s: %s\n", node->name (), malloc_state_names[state]); fprintf (dump_file, "%s: %s\n", node->name (), malloc_state_names[state]);
} }
...@@ -1902,12 +1856,10 @@ propagate_malloc (void) ...@@ -1902,12 +1856,10 @@ propagate_malloc (void)
FOR_EACH_FUNCTION (node) FOR_EACH_FUNCTION (node)
{ {
if (DECL_IS_MALLOC (node->decl)) if (DECL_IS_MALLOC (node->decl))
if (!has_function_state (node)) if (!funct_state_summaries->exists (node))
{ {
funct_state l = XCNEW (struct funct_state_d); funct_state fs = funct_state_summaries->get_create (node);
*l = varying_state; fs->malloc_state = STATE_MALLOC;
l->malloc_state = STATE_MALLOC;
set_function_state (node, l);
} }
} }
...@@ -1926,10 +1878,10 @@ propagate_malloc (void) ...@@ -1926,10 +1878,10 @@ propagate_malloc (void)
cgraph_node *node = order[i]; cgraph_node *node = order[i];
if (node->alias if (node->alias
|| !node->definition || !node->definition
|| !has_function_state (node)) || !funct_state_summaries->exists (node))
continue; continue;
funct_state l = get_function_state (node); funct_state l = funct_state_summaries->get_create (node);
/* FIXME: add support for indirect-calls. */ /* FIXME: add support for indirect-calls. */
if (node->indirect_calls) if (node->indirect_calls)
...@@ -1959,12 +1911,13 @@ propagate_malloc (void) ...@@ -1959,12 +1911,13 @@ propagate_malloc (void)
for (unsigned j = 0; j < callees.length (); j++) for (unsigned j = 0; j < callees.length (); j++)
{ {
cgraph_node *callee = callees[j]; cgraph_node *callee = callees[j];
if (!has_function_state (callee)) if (!funct_state_summaries->exists (node))
{ {
new_state = STATE_MALLOC_BOTTOM; new_state = STATE_MALLOC_BOTTOM;
break; break;
} }
malloc_state_e callee_state = get_function_state (callee)->malloc_state; malloc_state_e callee_state
= funct_state_summaries->get_create (callee)->malloc_state;
if (new_state < callee_state) if (new_state < callee_state)
new_state = callee_state; new_state = callee_state;
} }
...@@ -1977,9 +1930,9 @@ propagate_malloc (void) ...@@ -1977,9 +1930,9 @@ propagate_malloc (void)
} }
FOR_EACH_DEFINED_FUNCTION (node) FOR_EACH_DEFINED_FUNCTION (node)
if (has_function_state (node)) if (funct_state_summaries->exists (node))
{ {
funct_state l = get_function_state (node); funct_state l = funct_state_summaries->get_create (node);
if (!node->alias if (!node->alias
&& l->malloc_state == STATE_MALLOC && l->malloc_state == STATE_MALLOC
&& !node->global.inlined_to) && !node->global.inlined_to)
...@@ -2007,24 +1960,15 @@ unsigned int ...@@ -2007,24 +1960,15 @@ unsigned int
pass_ipa_pure_const:: pass_ipa_pure_const::
execute (function *) execute (function *)
{ {
struct cgraph_node *node;
bool remove_p; 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 /* Nothrow makes more function to not lead to return and improve
later analysis. */ later analysis. */
propagate_nothrow (); propagate_nothrow ();
propagate_malloc (); propagate_malloc ();
remove_p = propagate_pure_const (); remove_p = propagate_pure_const ();
/* Cleanup. */ delete funct_state_summaries;
FOR_EACH_FUNCTION (node)
if (has_function_state (node))
free (get_function_state (node));
funct_state_vec.release ();
return remove_p ? TODO_remove_functions : 0; return remove_p ? TODO_remove_functions : 0;
} }
...@@ -2045,12 +1989,7 @@ pass_ipa_pure_const::pass_ipa_pure_const(gcc::context *ctxt) ...@@ -2045,12 +1989,7 @@ pass_ipa_pure_const::pass_ipa_pure_const(gcc::context *ctxt)
0, /* function_transform_todo_flags_start */ 0, /* function_transform_todo_flags_start */
NULL, /* function_transform */ NULL, /* function_transform */
NULL), /* variable_transform */ NULL), /* variable_transform */
init_p(false), init_p (false) {}
function_insertion_hook_holder(NULL),
node_duplication_hook_holder(NULL),
node_removal_hook_holder(NULL)
{
}
ipa_opt_pass_d * ipa_opt_pass_d *
make_pass_ipa_pure_const (gcc::context *ctxt) make_pass_ipa_pure_const (gcc::context *ctxt)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment