Hi, this patch implements symmetric fix to ipa-pure-const. In this case it just slightly improves code quality for the case of recursive calls involving interposable functions.
Bootstrapped/regtested x86_64-linux, comitted. * ipa-pure-const.c (ignore_edge_for_pure_const): New function. (propagate_pure_const): Use it; fix comments and optimize loops. Index: ipa-pure-const.c =================================================================== --- ipa-pure-const.c (revision 231122) +++ ipa-pure-const.c (working copy) @@ -1157,6 +1164,17 @@ cdtor_p (cgraph_node *n, void *) return false; } +/* We only propagate across edges with non-interposable callee. */ + +static bool +ignore_edge_for_pure_const (struct cgraph_edge *e) +{ + enum availability avail; + e->callee->function_or_virtual_thunk_symbol (&avail); + return (avail <= AVAIL_INTERPOSABLE); +} + + /* Produce transitive closure over the callgraph and compute pure/const attributes. */ @@ -1172,7 +1190,8 @@ propagate_pure_const (void) struct ipa_dfs_info * w_info; bool remove_p = false; - order_pos = ipa_reduced_postorder (order, true, false, NULL); + order_pos = ipa_reduced_postorder (order, true, false, + ignore_edge_for_pure_const); if (dump_file) { cgraph_node::dump_cgraph (dump_file); @@ -1219,7 +1238,7 @@ propagate_pure_const (void) if (pure_const_state == IPA_NEITHER) break; - /* For overwritable nodes we can not assume anything. */ + /* For interposable nodes we can not assume anything. */ if (w->get_availability () == AVAIL_INTERPOSABLE) { worse_state (&pure_const_state, &looping, @@ -1228,7 +1247,7 @@ propagate_pure_const (void) if (dump_file && (dump_flags & TDF_DETAILS)) { fprintf (dump_file, - " Overwritable. state %s looping %i\n", + " Interposable. state %s looping %i\n", pure_const_names[w_l->state_previously_known], w_l->looping_previously_known); } @@ -1244,7 +1263,8 @@ propagate_pure_const (void) looping = true; /* Now walk the edges and merge in callee properties. */ - for (e = w->callees; e; e = e->next_callee) + for (e = w->callees; e && pure_const_state != IPA_NEITHER; + e = e->next_callee) { enum availability avail; struct cgraph_node *y = e->callee-> @@ -1302,11 +1322,10 @@ propagate_pure_const (void) if (pure_const_state == IPA_NEITHER) break; } - if (pure_const_state == IPA_NEITHER) - break; /* Now process the indirect call. */ - for (ie = w->indirect_calls; ie; ie = ie->next_callee) + for (ie = w->indirect_calls; + ie && pure_const_state != IPA_NEITHER; ie = ie->next_callee) { enum pure_const_state_e edge_state = IPA_CONST; bool edge_looping = false; @@ -1325,11 +1344,10 @@ propagate_pure_const (void) if (pure_const_state == IPA_NEITHER) break; } - if (pure_const_state == IPA_NEITHER) - break; /* And finally all loads and stores. */ - for (i = 0; w->iterate_reference (i, ref); i++) + for (i = 0; w->iterate_reference (i, ref) + && pure_const_state != IPA_NEITHER; i++) { enum pure_const_state_e ref_state = IPA_CONST; bool ref_looping = false; @@ -1419,7 +1437,8 @@ propagate_pure_const (void) && this_state > w_l->state_previously_known) { this_state = w_l->state_previously_known; - this_looping |= w_l->looping_previously_known; + if (this_state == IPA_NEITHER) + this_looping = w_l->looping_previously_known; } if (!this_looping && self_recursive_p (w)) this_looping = true;