> On Wed, Nov 12, 2014 at 02:49:30PM +0400, Maxim Ostapenko wrote: > > We used this code for IPA propagation of nonfreeing_call_p. It implemented > > with a separate pass, but it probably could be propagated in some existing > > one. This analysis doesn't seem to be costly thought, we didn't see any > > significant slowdown compiling big files. > > Here it is rewritten using ipa-pure-const which is where Richard/Honza > suggested it should be done in. > > I wonder if the nonfreeing_call_p function shouldn't be moved elsewhere > though (suggestion where), so that gimple.c doesn't need the cgraph > includes. > > In any case, bootstrapped/regtested on x86_64-linux and i686-linux. > > 2014-11-12 Jakub Jelinek <ja...@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_can_free): New function. > (pass_ipa_pure_const::execute): Call it. > * 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. > * 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. > > --- gcc/ipa-pure-const.c.jj 2014-11-12 18:32:56.351139726 +0100 > +++ gcc/ipa-pure-const.c 2014-11-12 21:11:08.574354600 +0100 > @@ -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 ca > 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 ca > break; > } > } > + else if (gimple_call_internal_p (call) && !nonfreeing_call_p (call)) > + local->can_free = true;
Actually I think you want to do this for can_throw, too. We probably do not have throwing internal calls, but it is better to be safe. > +/* Produce transitive closure over the callgraph and compute can_free > + attributes. */ > + > +static void > +propagate_can_free (void) > +{ > + struct cgraph_node *node; > + struct cgraph_node *w; > + struct cgraph_node **order > + = XCNEWVEC (struct cgraph_node *, symtab->cgraph_count); > + int order_pos; > + int i; > + struct ipa_dfs_info *w_info; > + > + order_pos = ipa_reduced_postorder (order, true, false, NULL); > + if (dump_file) > + { > + cgraph_node::dump_cgraph (dump_file); > + ipa_print_order (dump_file, "reduced", order, order_pos); > + } The propagation seems fine, but I wonder if we won't get better memory locality doing this during the propagation of pure/const? nothrow flag goes in separate loop because knowledge of nothrow helps pure/const to work better. Also one can ignore call edges that are !can_thros_externally to get fewer cycles, but apparently this got never implemented. > && gimple_call_flags (call) & ECF_LEAF) > return true; > > - return false; > + tree fndecl = gimple_call_fndecl (call); > + if (!fndecl) > + return false; > + struct cgraph_node *n = cgraph_node::get (fndecl); You want to walk aliases, cgraph_node::get (fndecl)->function_symbol (&availability) > + if (!n || n->get_availability () <= AVAIL_INTERPOSABLE) and use availability here. OK with this change. Honza