Hi, code removing references to indirectly-inlined functions can remove a few too many when speculative devirtualization gets into the picture. Although we already handle the case when speculative devirtualization clones an edge with a CONST jump function by also cloning the appropriate reference, we do nothing when cloning a PASS_THROUGH jump function. However, inlining can later convert this into a CONST jump function and when that gets deleted, the reference is dropped (as a part of speculative devirtualization resolution). Eventually this leads to the function being removed as unreachable and missing in the final link. This is fixed by the following patch which increments controlled use counter of formal parameters when this kind of edge duplication.
I have also attempted to add a hunk to the edge removal hook that would decrement the counter in these situation (dropping the edge after all means the call will never happen). However, I have run into ordering issues within indirect inlining (and speculative devirtualization resolution which happens as a part of making an edge direct). So at the moment I'm posting only this fix and will work on the removal hook later. Bootstrapped and tested on x86_64-linux, I have also successfully LTO-built Firefox with the patch (when before it was failing). Thanks, Martin 2014-09-19 Martin Jambor <mjam...@suse.cz> * ipa-prop.c (ipa_edge_duplication_hook): Update controlled_use_count when duplicating a PASS_THROUGH jump function when creating a speculative edge. diff --git a/gcc/ipa-prop.c b/gcc/ipa-prop.c index bbb417d..29c8681 100644 --- a/gcc/ipa-prop.c +++ b/gcc/ipa-prop.c @@ -3643,6 +3643,21 @@ ipa_edge_duplication_hook (struct cgraph_edge *src, struct cgraph_edge *dst, dst_jf->value.constant.rdesc = dst_rdesc; } } + else if (dst_jf->type == IPA_JF_PASS_THROUGH + && src->caller == dst->caller) + { + struct cgraph_node *inline_root = dst->caller->global.inlined_to + ? dst->caller->global.inlined_to : dst->caller; + struct ipa_node_params *root_info = IPA_NODE_REF (inline_root); + int idx = ipa_get_jf_pass_through_formal_id (dst_jf); + + int c = ipa_get_controlled_uses (root_info, idx); + if (c != IPA_UNDESCRIBED_USE) + { + c++; + ipa_set_controlled_uses (root_info, idx, c); + } + } } }