Hi, this fixes indirect call speculation ICE Martin (Liska) reduced from spec GCC. The problem here was in resolve_speculation that if called to resolve the second edge in multi-target speculative call resolved first on instead. This is bug I did not catch during the API change. Other problem is that redirect_call_stmt_to_callee if called from inliner is called on direct part of speculative call while it expects indirect. This is checking only failure but rahter than removing sanity check I switch to indirect edge.
profiled-lto-bootstrapped x86_64-linux and comitted. Honza 2020-01-29 Jan Hubicka <hubi...@ucw.cz> * cgraph.c (cgraph_edge::resolve_speculation): Only lookup direct edge if called on indirect edge. (cgraph_edge::redirect_call_stmt_to_callee): Lookup indirect edge of speculative call if needed. gcc/testsuite/ChangeLog: 2020-01-29 Jan Hubicka <hubi...@ucw.cz> * gcc.dg/tree-prof/indir-call-prof-2.c: New testcase. diff --git a/gcc/cgraph.c b/gcc/cgraph.c index 3e50b0bc380..294b2d392fd 100644 --- a/gcc/cgraph.c +++ b/gcc/cgraph.c @@ -1189,7 +1189,10 @@ cgraph_edge::resolve_speculation (cgraph_edge *edge, tree callee_decl) ipa_ref *ref; gcc_assert (edge->speculative && (!callee_decl || edge->callee)); - e2 = edge->first_speculative_call_target (); + if (!edge->callee) + e2 = edge->first_speculative_call_target (); + else + e2 = edge; ref = e2->speculative_call_target_ref (); edge = edge->speculative_call_indirect_edge (); if (!callee_decl @@ -1364,7 +1367,8 @@ cgraph_edge::redirect_call_stmt_to_callee (cgraph_edge *e) /* If there already is an direct call (i.e. as a result of inliner's substitution), forget about speculating. */ if (decl) - e = make_direct (e, cgraph_node::get (decl)); + e = make_direct (e->speculative_call_indirect_edge (), + cgraph_node::get (decl)); else { /* Be sure we redirect all speculative targets before poking diff --git a/gcc/testsuite/gcc.dg/tree-prof/indir-call-prof-2.c b/gcc/testsuite/gcc.dg/tree-prof/indir-call-prof-2.c index 61612b5b628..bbba0521018 100644 --- a/gcc/testsuite/gcc.dg/tree-prof/indir-call-prof-2.c +++ b/gcc/testsuite/gcc.dg/tree-prof/indir-call-prof-2.c @@ -1,25 +1,28 @@ /* { dg-options "-O2 -fno-early-inlining -fdump-ipa-profile-optimized -fdump-ipa-afdo" } */ volatile int one; -static -int add1 (int val) +static int +add1 (int val) { - return val+=one; + return val += one; } -static -int sub1 (int val) + +static int +sub1 (int val) { - return val-=one; + return val -= one; } -static -int do_op (int val, int (*fnptr) (int)) + +static int +do_op (int val, int (*fnptr) (int)) { return fnptr (val); } + int -main(void) +main (void) { - int i,val; - for (i=0;i<100000;i++) + int i, val = 0; + for (i = 0; i < 100000; i++) { val = do_op (val, add1); val = do_op (val, sub1); diff --git a/libgcc/libgcov-merge.c b/libgcc/libgcov-merge.c index 19b8ee72ae9..801037d0d64 100644 --- a/libgcc/libgcov-merge.c +++ b/libgcc/libgcov-merge.c @@ -115,7 +115,7 @@ merge_topn_values_set (gcov_type *counters) continue; unsigned j; - int slot = -1; + int slot = 0; for (j = 0; j < GCOV_TOPN_VALUES; j++) { @@ -124,24 +124,15 @@ merge_topn_values_set (gcov_type *counters) counters[2 * j + 1] += read_counters[2 * i + 1]; break; } - else if (counters[2 * j + 1] == 0) + if (counters[2 * j + 1] < counters[2 * slot + 1]) slot = j; } - if (j == GCOV_TOPN_VALUES) + if (j == GCOV_TOPN_VALUES + && counters[2 * slot + 1] < read_counters[2 * i + 1]) { - if (slot > 0) - { - /* If we found empty slot, add the value. */ - counters[2 * slot] = read_counters[2 * i]; - counters[2 * slot + 1] = read_counters[2 * i + 1]; - } - else - { - /* We haven't found a slot, bail out. */ - counters[1] = -1; - return; - } + counters[2 * slot] = read_counters[2 * i]; + counters[2 * slot + 1] = read_counters[2 * i + 1]; } } }