Hi, this patch splits call predictor to direct/indirect/polymorphic variant. The motivation is that the predictor seems to do poor job on GAP benchmark predicting that path containing an indirect call is unlikely. These calls are quite specific, so it makes sense to have separate predictor for them.
The values was measured by Martin on SPEC2k6 and will need tweaking to get gap performance back. I think this is OK given that we have quite small sample of benchmarks having indirect call in the hot loop, but I would like to do that incrementally. Bootstrapped/regtested x86_64-linux, comitted. Honza PR middle-end/77484 * predict.def (PRED_CALL): Update hitrate. (PRED_INDIR_CALL, PRED_POLYMORPHIC_CALL): New predictors. * predict.c (tree_estimate_probability_bb): Split CALL predictor into direct/indirect/polymorphic variants. Index: predict.def =================================================================== --- predict.def (revision 243992) +++ predict.def (working copy) @@ -116,7 +116,13 @@ DEF_PREDICTOR (PRED_TREE_OPCODE_NONEQUAL DEF_PREDICTOR (PRED_TREE_FPOPCODE, "fp_opcode (on trees)", HITRATE (90), 0) /* Branch guarding call is probably taken. */ -DEF_PREDICTOR (PRED_CALL, "call", HITRATE (67), 0) +DEF_PREDICTOR (PRED_CALL, "call", HITRATE (55), 0) + +/* PRED_CALL is not very reliable predictor and it turns out to be even + less reliable for indirect calls and polymorphic calls. For spec2k6 + the predictio nis slightly in the direction of taking the call. */ +DEF_PREDICTOR (PRED_INDIR_CALL, "indirect call", HITRATE (51), 0) +DEF_PREDICTOR (PRED_POLYMORPHIC_CALL, "polymorphic call", HITRATE (58), 0) /* Recursive calls are usually not taken or the function will recurse indefinitely. */ Index: predict.c =================================================================== --- predict.c (revision 243992) +++ predict.c (working copy) @@ -2786,7 +2786,12 @@ tree_estimate_probability_bb (basic_bloc something exceptional. */ && gimple_has_side_effects (stmt)) { - predict_edge_def (e, PRED_CALL, NOT_TAKEN); + if (gimple_call_fndecl (stmt)) + predict_edge_def (e, PRED_CALL, NOT_TAKEN); + else if (virtual_method_call_p (gimple_call_fn (stmt))) + predict_edge_def (e, PRED_POLYMORPHIC_CALL, TAKEN); + else + predict_edge_def (e, PRED_INDIR_CALL, TAKEN); break; } }