diff options
author | jakub <jakub@138bc75d-0d04-0410-961f-82ee72b054a4> | 2014-11-14 17:46:50 +0000 |
---|---|---|
committer | jakub <jakub@138bc75d-0d04-0410-961f-82ee72b054a4> | 2014-11-14 17:46:50 +0000 |
commit | 04c849b31c5935979173f0b33f6a92506324ddd5 (patch) | |
tree | a5f3f2ac60cf67edecc73331df1bbb55654423a3 /gcc | |
parent | f407b74ad3650ad40b2fb3d1751f362d5b81b8ae (diff) | |
download | gcc-04c849b31c5935979173f0b33f6a92506324ddd5.tar.gz |
* ipa-pure-const.c (struct funct_state_d): Add can_free field.
(varying_state): Add true for can_free.
(check_call): For builtin or internal !nonfreeing_call_p set
local->can_free.
(check_stmt): For asm volatile and asm with "memory" set
local->can_free.
(analyze_function): Clear local->can_free initially, continue
calling check_stmt until all flags are computed, dump can_free
flag.
(pure_const_write_summary): Write can_free flag.
(pure_const_read_summary): Read it back.
(propagate_pure_const): Propagate also can_free flag, set
w->nonfreeing_fn if it is false after propagation.
* cgraph.h (cgraph_node): Add nonfreeing_fn member.
* gimple.c: Include ipa-ref.h, lto-streamer.h and cgraph.h.
(nonfreeing_call_p): Return cgraph nonfreeing_fn flag if set.
Also return true for IFN_ABNORMAL_DISPATCHER.
* cgraph.c (cgraph_node::dump): Dump nonfreeing_fn flag.
* lto-cgraph.c (lto_output_node): Write nonfreeing_fn flag.
(input_overwrite_node): Read it back.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@217582 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/ChangeLog | 23 | ||||
-rw-r--r-- | gcc/cgraph.c | 2 | ||||
-rw-r--r-- | gcc/cgraph.h | 4 | ||||
-rw-r--r-- | gcc/gimple.c | 28 | ||||
-rw-r--r-- | gcc/ipa-pure-const.c | 61 | ||||
-rw-r--r-- | gcc/lto-cgraph.c | 2 |
6 files changed, 113 insertions, 7 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index e5ff6e9a615..c5ea4811458 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,4 +1,27 @@ 2014-11-14 Jakub Jelinek <jakub@redhat.com> + + * ipa-pure-const.c (struct funct_state_d): Add can_free field. + (varying_state): Add true for can_free. + (check_call): For builtin or internal !nonfreeing_call_p set + local->can_free. + (check_stmt): For asm volatile and asm with "memory" set + local->can_free. + (analyze_function): Clear local->can_free initially, continue + calling check_stmt until all flags are computed, dump can_free + flag. + (pure_const_write_summary): Write can_free flag. + (pure_const_read_summary): Read it back. + (propagate_pure_const): Propagate also can_free flag, set + w->nonfreeing_fn if it is false after propagation. + * cgraph.h (cgraph_node): Add nonfreeing_fn member. + * gimple.c: Include ipa-ref.h, lto-streamer.h and cgraph.h. + (nonfreeing_call_p): Return cgraph nonfreeing_fn flag if set. + Also return true for IFN_ABNORMAL_DISPATCHER. + * cgraph.c (cgraph_node::dump): Dump nonfreeing_fn flag. + * lto-cgraph.c (lto_output_node): Write nonfreeing_fn flag. + (input_overwrite_node): Read it back. + +2014-11-14 Jakub Jelinek <jakub@redhat.com> Marek Polacek <polacek@redhat.com> * sanopt.c: Include tree-ssa-operands.h. diff --git a/gcc/cgraph.c b/gcc/cgraph.c index 8dcccbf19c6..a66c9c0ea75 100644 --- a/gcc/cgraph.c +++ b/gcc/cgraph.c @@ -1995,6 +1995,8 @@ cgraph_node::dump (FILE *f) fprintf (f, " tm_clone"); if (icf_merged) fprintf (f, " icf_merged"); + if (nonfreeing_fn) + fprintf (f, " nonfreeing_fn"); if (DECL_STATIC_CONSTRUCTOR (decl)) fprintf (f," static_constructor (priority:%i)", get_init_priority ()); if (DECL_STATIC_DESTRUCTOR (decl)) diff --git a/gcc/cgraph.h b/gcc/cgraph.h index 82222217898..e9a14c4d492 100644 --- a/gcc/cgraph.h +++ b/gcc/cgraph.h @@ -1267,6 +1267,10 @@ public: /* True when function is clone created for Pointer Bounds Checker instrumentation. */ unsigned instrumentation_clone : 1; + /* True if call to node can't result in a call to free, munmap or + other operation that could make previously non-trapping memory + accesses trapping. */ + unsigned nonfreeing_fn : 1; }; /* A cgraph node set is a collection of cgraph nodes. A cgraph node diff --git a/gcc/gimple.c b/gcc/gimple.c index ac753650e18..f8459a448cb 100644 --- a/gcc/gimple.c +++ b/gcc/gimple.c @@ -58,6 +58,9 @@ along with GCC; see the file COPYING3. If not see #include "bitmap.h" #include "stringpool.h" #include "tree-ssanames.h" +#include "ipa-ref.h" +#include "lto-streamer.h" +#include "cgraph.h" /* All the tuples have their operand vector (if present) at the very bottom @@ -2538,11 +2541,28 @@ nonfreeing_call_p (gimple call) default: return true; } - else if (gimple_call_internal_p (call) - && gimple_call_flags (call) & ECF_LEAF) - return true; + else if (gimple_call_internal_p (call)) + switch (gimple_call_internal_fn (call)) + { + case IFN_ABNORMAL_DISPATCHER: + return true; + default: + if (gimple_call_flags (call) & ECF_LEAF) + return true; + return false; + } - return false; + tree fndecl = gimple_call_fndecl (call); + if (!fndecl) + return false; + struct cgraph_node *n = cgraph_node::get (fndecl); + if (!n) + return false; + enum availability availability; + n = n->function_symbol (&availability); + if (!n || availability <= AVAIL_INTERPOSABLE) + return false; + return n->nonfreeing_fn; } /* Callback for walk_stmt_load_store_ops. diff --git a/gcc/ipa-pure-const.c b/gcc/ipa-pure-const.c index 6f7b32c12bc..a55288d7ba4 100644 --- a/gcc/ipa-pure-const.c +++ b/gcc/ipa-pure-const.c @@ -112,11 +112,15 @@ struct funct_state_d bool looping; bool can_throw; + + /* If function can call free, munmap or otherwise make previously + non-trapping memory accesses trapping. */ + 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 }; + = { IPA_NEITHER, IPA_NEITHER, true, true, true, true }; typedef struct funct_state_d * funct_state; @@ -559,6 +563,10 @@ check_call (funct_state local, gimple call, bool ipa) enum pure_const_state_e call_state; bool call_looping; + if (gimple_call_builtin_p (call, BUILT_IN_NORMAL) + && !nonfreeing_call_p (call)) + local->can_free = true; + if (special_builtin_state (&call_state, &call_looping, callee_t)) { worse_state (&local->pure_const_state, &local->looping, @@ -589,6 +597,8 @@ check_call (funct_state local, gimple call, bool ipa) break; } } + else if (gimple_call_internal_p (call) && !nonfreeing_call_p (call)) + local->can_free = true; /* When not in IPA mode, we can still handle self recursion. */ if (!ipa && callee_t @@ -753,6 +763,7 @@ check_stmt (gimple_stmt_iterator *gsip, funct_state local, bool ipa) fprintf (dump_file, " memory asm clobber is not const/pure\n"); /* Abandon all hope, ye who enter here. */ local->pure_const_state = IPA_NEITHER; + local->can_free = true; } if (gimple_asm_volatile_p (stmt)) { @@ -760,7 +771,8 @@ check_stmt (gimple_stmt_iterator *gsip, funct_state local, bool ipa) fprintf (dump_file, " volatile is not const/pure\n"); /* Abandon all hope, ye who enter here. */ local->pure_const_state = IPA_NEITHER; - local->looping = true; + local->looping = true; + local->can_free = true; } return; default: @@ -785,6 +797,7 @@ analyze_function (struct cgraph_node *fn, bool ipa) l->looping_previously_known = true; l->looping = false; l->can_throw = false; + l->can_free = false; state_from_flags (&l->state_previously_known, &l->looping_previously_known, flags_from_decl_or_type (fn->decl), fn->cannot_return_p ()); @@ -815,7 +828,10 @@ analyze_function (struct cgraph_node *fn, bool ipa) gsi_next (&gsi)) { check_stmt (&gsi, l, ipa); - if (l->pure_const_state == IPA_NEITHER && l->looping && l->can_throw) + if (l->pure_const_state == IPA_NEITHER + && l->looping + && l->can_throw + && l->can_free) goto end; } } @@ -882,6 +898,8 @@ end: fprintf (dump_file, "Function is locally const.\n"); if (l->pure_const_state == IPA_PURE) fprintf (dump_file, "Function is locally pure.\n"); + if (l->can_free) + fprintf (dump_file, "Function can locally free.\n"); } return l; } @@ -1021,6 +1039,7 @@ pure_const_write_summary (void) bp_pack_value (&bp, fs->looping_previously_known, 1); bp_pack_value (&bp, fs->looping, 1); bp_pack_value (&bp, fs->can_throw, 1); + bp_pack_value (&bp, fs->can_free, 1); streamer_write_bitpack (&bp); } } @@ -1080,6 +1099,7 @@ pure_const_read_summary (void) fs->looping_previously_known = bp_unpack_value (&bp, 1); fs->looping = bp_unpack_value (&bp, 1); fs->can_throw = bp_unpack_value (&bp, 1); + fs->can_free = bp_unpack_value (&bp, 1); if (dump_file) { int flags = flags_from_decl_or_type (node->decl); @@ -1102,6 +1122,8 @@ pure_const_read_summary (void) fprintf (dump_file," function is previously known looping\n"); if (fs->can_throw) fprintf (dump_file," function is locally throwing\n"); + if (fs->can_free) + fprintf (dump_file," function can locally free\n"); } } @@ -1347,6 +1369,33 @@ propagate_pure_const (void) pure_const_names [pure_const_state], looping); + /* Find the worst state of can_free for any node in the cycle. */ + bool can_free = false; + w = node; + while (w && !can_free) + { + struct cgraph_edge *e; + funct_state w_l = get_function_state (w); + + if (w_l->can_free + || w->get_availability () == AVAIL_INTERPOSABLE + || w->indirect_calls) + can_free = true; + + for (e = w->callees; e && !can_free; e = e->next_callee) + { + enum availability avail; + struct cgraph_node *y = e->callee->function_symbol (&avail); + + if (avail > AVAIL_INTERPOSABLE) + can_free = get_function_state (y)->can_free; + else + can_free = true; + } + w_info = (struct ipa_dfs_info *) w->aux; + w = w_info->next_cycle; + } + /* Copy back the region's pure_const_state which is shared by all nodes in the region. */ w = node; @@ -1356,6 +1405,12 @@ propagate_pure_const (void) enum pure_const_state_e this_state = pure_const_state; bool this_looping = looping; + w_l->can_free = can_free; + w->nonfreeing_fn = !can_free; + if (!can_free && dump_file) + fprintf (dump_file, "Function found not to call free: %s\n", + w->name ()); + if (w_l->state_previously_known != IPA_NEITHER && this_state > w_l->state_previously_known) { diff --git a/gcc/lto-cgraph.c b/gcc/lto-cgraph.c index b29d1b51a38..3ce2367a3bf 100644 --- a/gcc/lto-cgraph.c +++ b/gcc/lto-cgraph.c @@ -562,6 +562,7 @@ lto_output_node (struct lto_simple_output_block *ob, struct cgraph_node *node, bp_pack_value (&bp, node->tm_clone, 1); bp_pack_value (&bp, node->calls_comdat_local, 1); bp_pack_value (&bp, node->icf_merged, 1); + bp_pack_value (&bp, node->nonfreeing_fn, 1); bp_pack_value (&bp, node->thunk.thunk_p && !boundary_p, 1); bp_pack_enum (&bp, ld_plugin_symbol_resolution, LDPR_NUM_KNOWN, node->resolution); @@ -1168,6 +1169,7 @@ input_overwrite_node (struct lto_file_decl_data *file_data, node->tm_clone = bp_unpack_value (bp, 1); node->calls_comdat_local = bp_unpack_value (bp, 1); node->icf_merged = bp_unpack_value (bp, 1); + node->nonfreeing_fn = bp_unpack_value (bp, 1); node->thunk.thunk_p = bp_unpack_value (bp, 1); node->resolution = bp_unpack_enum (bp, ld_plugin_symbol_resolution, LDPR_NUM_KNOWN); |