Hi, as we discover targets of previously indirect calls in ipa-inline and ipa-cp, we sometimes figure out that the targets are not a function. One typical example is when NULL is passed as a function pointer parameter, another is when C++ member-pointer points to a virtual function and the overloaded field of the structure which can also hold pointers to non-virtual methods contains odd integer constants.
I have gone through all the cases when this happens when LTO building Mozilla Firefox and verified all of them were OK and legal. Because no such call to a non-function can ever occur in a legal program, I have decided to turn them into calls of builting_unreachable, which then could help further optimizations. Because calls to builtin_unreachable is not cgraph_maybe_hot_edge_p, whereas an indirect call with an unknown destination is, this change often triggered assertion tree-ipa-inline-transform.c:263. I have discussed this with Honza and he has agreed to switch the check off when there are newly discovered direct edges. The patch has passed bootstrap and is undergoing testing now. OK for trunk if it passes? Thanks, Martin 2013-05-09 Martin Jambor <mjam...@suse.cz> * ipa-prop.c (ipa_make_edge_direct_to_target): Redirect calls to non-functions to builtin_unreachable. * ipa-inline-transform.c (inline_call): Do not assert estimates were correct when new direct edges were discovered. Index: src/gcc/ipa-prop.c =================================================================== --- src.orig/gcc/ipa-prop.c +++ src/gcc/ipa-prop.c @@ -2200,6 +2200,7 @@ ipa_make_edge_direct_to_target (struct c { struct cgraph_node *callee; struct inline_edge_summary *es = inline_edge_summary (ie); + bool unreachable = false; if (TREE_CODE (target) == ADDR_EXPR) target = TREE_OPERAND (target, 0); @@ -2210,12 +2211,17 @@ ipa_make_edge_direct_to_target (struct c { if (dump_file) fprintf (dump_file, "ipa-prop: Discovered direct call to non-function" - " in %s/%i.\n", + " in %s/%i, making it unreachable.\n", cgraph_node_name (ie->caller), ie->caller->symbol.order); - return NULL; + target = builtin_decl_implicit (BUILT_IN_UNREACHABLE); + callee = cgraph_get_create_node (target); + unreachable = true; } + else + callee = cgraph_get_node (target); } - callee = cgraph_get_node (target); + else + callee = cgraph_get_node (target); /* Because may-edges are not explicitely represented and vtable may be external, we may create the first reference to the object in the unit. */ @@ -2252,7 +2258,7 @@ ipa_make_edge_direct_to_target (struct c - eni_size_weights.call_cost); es->call_stmt_time -= (eni_time_weights.indirect_call_cost - eni_time_weights.call_cost); - if (dump_file) + if (dump_file && !unreachable) { fprintf (dump_file, "ipa-prop: Discovered %s call to a known target " "(%s/%i -> %s/%i), for stmt ", Index: src/gcc/ipa-inline-transform.c =================================================================== --- src.orig/gcc/ipa-inline-transform.c +++ src/gcc/ipa-inline-transform.c @@ -260,7 +260,7 @@ inline_call (struct cgraph_edge *e, bool #ifdef ENABLE_CHECKING /* Verify that estimated growth match real growth. Allow off-by-one error due to INLINE_SIZE_SCALE roudoff errors. */ - gcc_assert (!update_overall_summary || !overall_size + gcc_assert (!update_overall_summary || !overall_size || new_edges_found || abs (estimated_growth - (new_size - old_size)) <= 1 /* FIXME: a hack. Edges with false predicate are accounted wrong, we should remove them from callgraph. */