static basic_block find_block_to_duplicate_for_splitting_paths (basic_block latch) { /* We should have simple latches at this point. So the latch should have a single successor. This implies the predecessor of the latch likely has the loop exit. And it's that predecessor we're most interested in. To keep things simple, we're going to require that the latch have a single predecessor too. */ if (single_succ_p (latch) && single_pred_p (latch)) { basic_block bb = get_immediate_dominator (CDI_DOMINATORS, latch); gcc_assert (single_pred_edge (latch)->src == bb); /* If BB has been marked as not to be duplicated, then honor that request. */ if (ignore_bb_p (bb)) return NULL; gimple *last = gsi_stmt (gsi_last_nondebug_bb (bb)); /* The immediate dominator of the latch must end in a conditional. */ if (!last || gimple_code (last) != GIMPLE_COND) return NULL; /* We're hoping that BB is a join point for an IF-THEN-ELSE diamond region. Verify that it is. First, verify that BB has two predecessors (each arm of the IF-THEN-ELSE) and two successors (the latch and exit). */ if (EDGE_COUNT (bb->preds) == 2 && EDGE_COUNT (bb->succs) == 2) { /* Now verify that BB's immediate dominator ends in a conditional as well. */ basic_block bb_idom = get_immediate_dominator (CDI_DOMINATORS, bb); gimple *last = gsi_stmt (gsi_last_nondebug_bb (bb_idom)); if (!last || gimple_code (last) != GIMPLE_COND) return NULL; /* And that BB's immediate dominator's successors are the predecessors of BB. */ if (!find_edge (bb_idom, EDGE_PRED (bb, 0)->src) || !find_edge (bb_idom, EDGE_PRED (bb, 1)->src)) return NULL; /* And that the predecessors of BB each have a single successor. */ if (!single_succ_p (EDGE_PRED (bb, 0)->src) || !single_succ_p (EDGE_PRED (bb, 1)->src)) return NULL; /* So at this point we have a simple diamond for an IF-THEN-ELSE construct starting at BB_IDOM, with a join point at BB. BB pass control outside the loop or to the loop latch. We're going to want to create two duplicates of BB, one for each successor of BB_IDOM. */ return bb; } } return NULL; }
static edge find_best_successor (basic_block bb) { edge e; edge best = NULL; for (e = bb->succ; e; e = e->succ_next) if (!best || better_p (e, best)) best = e; if (!best || ignore_bb_p (best->dest)) return NULL; if (best->probability <= probability_cutoff) return NULL; return best; }
static edge find_best_successor (basic_block bb) { edge e; edge best = NULL; edge_iterator ei; FOR_EACH_EDGE (e, ei, bb->succs) if (!best || better_p (e, best)) best = e; if (!best || ignore_bb_p (best->dest)) return NULL; if (best->probability <= probability_cutoff) return NULL; return best; }
static edge find_best_predecessor (basic_block bb) { edge e; edge best = NULL; for (e = bb->pred; e; e = e->pred_next) if (!best || better_p (e, best)) best = e; if (!best || ignore_bb_p (best->src)) return NULL; if (EDGE_FREQUENCY (best) * REG_BR_PROB_BASE < bb->frequency * branch_ratio_cutoff) return NULL; return best; }
static edge find_best_predecessor (basic_block bb) { edge e; edge best = NULL; edge_iterator ei; FOR_EACH_EDGE (e, ei, bb->preds) if (!best || better_p (e, best)) best = e; if (!best || ignore_bb_p (best->src)) return NULL; if (EDGE_FREQUENCY (best) * REG_BR_PROB_BASE < bb->frequency * branch_ratio_cutoff) return NULL; return best; }
static bool tail_duplicate (void) { auto_vec<fibonacci_node<long, basic_block_def>*> blocks; blocks.safe_grow_cleared (last_basic_block_for_fn (cfun)); basic_block *trace = XNEWVEC (basic_block, n_basic_blocks_for_fn (cfun)); int *counts = XNEWVEC (int, last_basic_block_for_fn (cfun)); int ninsns = 0, nduplicated = 0; gcov_type weighted_insns = 0, traced_insns = 0; fibonacci_heap<long, basic_block_def> heap (LONG_MIN); gcov_type cover_insns; int max_dup_insns; basic_block bb; bool changed = false; /* Create an oversized sbitmap to reduce the chance that we need to resize it. */ bb_seen = sbitmap_alloc (last_basic_block_for_fn (cfun) * 2); bitmap_clear (bb_seen); initialize_original_copy_tables (); if (profile_info && flag_branch_probabilities) probability_cutoff = PARAM_VALUE (TRACER_MIN_BRANCH_PROBABILITY_FEEDBACK); else probability_cutoff = PARAM_VALUE (TRACER_MIN_BRANCH_PROBABILITY); probability_cutoff = REG_BR_PROB_BASE / 100 * probability_cutoff; branch_ratio_cutoff = (REG_BR_PROB_BASE / 100 * PARAM_VALUE (TRACER_MIN_BRANCH_RATIO)); FOR_EACH_BB_FN (bb, cfun) { int n = count_insns (bb); if (!ignore_bb_p (bb)) blocks[bb->index] = heap.insert (-bb->frequency, bb); counts [bb->index] = n; ninsns += n; weighted_insns += n * bb->frequency; }
static bool tail_duplicate (void) { fibnode_t *blocks = XCNEWVEC (fibnode_t, last_basic_block); basic_block *trace = XNEWVEC (basic_block, n_basic_blocks); int *counts = XNEWVEC (int, last_basic_block); int ninsns = 0, nduplicated = 0; gcov_type weighted_insns = 0, traced_insns = 0; fibheap_t heap = fibheap_new (); gcov_type cover_insns; int max_dup_insns; basic_block bb; bool changed = false; /* Create an oversized sbitmap to reduce the chance that we need to resize it. */ bb_seen = sbitmap_alloc (last_basic_block * 2); bitmap_clear (bb_seen); initialize_original_copy_tables (); if (profile_info && flag_branch_probabilities) probability_cutoff = PARAM_VALUE (TRACER_MIN_BRANCH_PROBABILITY_FEEDBACK); else probability_cutoff = PARAM_VALUE (TRACER_MIN_BRANCH_PROBABILITY); probability_cutoff = REG_BR_PROB_BASE / 100 * probability_cutoff; branch_ratio_cutoff = (REG_BR_PROB_BASE / 100 * PARAM_VALUE (TRACER_MIN_BRANCH_RATIO)); FOR_EACH_BB (bb) { int n = count_insns (bb); if (!ignore_bb_p (bb)) blocks[bb->index] = fibheap_insert (heap, -bb->frequency, bb); counts [bb->index] = n; ninsns += n; weighted_insns += n * bb->frequency; } if (profile_info && flag_branch_probabilities) cover_insns = PARAM_VALUE (TRACER_DYNAMIC_COVERAGE_FEEDBACK); else cover_insns = PARAM_VALUE (TRACER_DYNAMIC_COVERAGE); cover_insns = (weighted_insns * cover_insns + 50) / 100; max_dup_insns = (ninsns * PARAM_VALUE (TRACER_MAX_CODE_GROWTH) + 50) / 100; while (traced_insns < cover_insns && nduplicated < max_dup_insns && !fibheap_empty (heap)) { basic_block bb = (basic_block) fibheap_extract_min (heap); int n, pos; if (!bb) break; blocks[bb->index] = NULL; if (ignore_bb_p (bb)) continue; gcc_assert (!bb_seen_p (bb)); n = find_trace (bb, trace); bb = trace[0]; traced_insns += bb->frequency * counts [bb->index]; if (blocks[bb->index]) { fibheap_delete_node (heap, blocks[bb->index]); blocks[bb->index] = NULL; } for (pos = 1; pos < n; pos++) { basic_block bb2 = trace[pos]; if (blocks[bb2->index]) { fibheap_delete_node (heap, blocks[bb2->index]); blocks[bb2->index] = NULL; } traced_insns += bb2->frequency * counts [bb2->index]; if (EDGE_COUNT (bb2->preds) > 1 && can_duplicate_block_p (bb2) /* We have the tendency to duplicate the loop header of all do { } while loops. Do not do that - it is not profitable and it might create a loop with multiple entries or at least rotate the loop. */ && (!current_loops || bb2->loop_father->header != bb2)) { edge e; basic_block copy; nduplicated += counts [bb2->index]; e = find_edge (bb, bb2); copy = duplicate_block (bb2, e, bb); flush_pending_stmts (e); add_phi_args_after_copy (©, 1, NULL); /* Reconsider the original copy of block we've duplicated. Removing the most common predecessor may make it to be head. */ blocks[bb2->index] = fibheap_insert (heap, -bb2->frequency, bb2); if (dump_file) fprintf (dump_file, "Duplicated %i as %i [%i]\n", bb2->index, copy->index, copy->frequency); bb2 = copy; changed = true; } mark_bb_seen (bb2); bb = bb2; /* In case the trace became infrequent, stop duplicating. */ if (ignore_bb_p (bb)) break; } if (dump_file) fprintf (dump_file, " covered now %.1f\n\n", traced_insns * 100.0 / weighted_insns); } if (dump_file) fprintf (dump_file, "Duplicated %i insns (%i%%)\n", nduplicated, nduplicated * 100 / ninsns); free_original_copy_tables (); sbitmap_free (bb_seen); free (blocks); free (trace); free (counts); fibheap_delete (heap); return changed; }
static void tail_duplicate (void) { fibnode_t *blocks = XCNEWVEC (fibnode_t, last_basic_block); basic_block *trace = XNEWVEC (basic_block, n_basic_blocks); int *counts = XNEWVEC (int, last_basic_block); int ninsns = 0, nduplicated = 0; gcov_type weighted_insns = 0, traced_insns = 0; fibheap_t heap = fibheap_new (); gcov_type cover_insns; int max_dup_insns; basic_block bb; if (profile_info && flag_branch_probabilities) probability_cutoff = PARAM_VALUE (TRACER_MIN_BRANCH_PROBABILITY_FEEDBACK); else probability_cutoff = PARAM_VALUE (TRACER_MIN_BRANCH_PROBABILITY); probability_cutoff = REG_BR_PROB_BASE / 100 * probability_cutoff; branch_ratio_cutoff = (REG_BR_PROB_BASE / 100 * PARAM_VALUE (TRACER_MIN_BRANCH_RATIO)); FOR_EACH_BB (bb) { int n = count_insns (bb); if (!ignore_bb_p (bb)) blocks[bb->index] = fibheap_insert (heap, -bb->frequency, bb); counts [bb->index] = n; ninsns += n; weighted_insns += n * bb->frequency; } if (profile_info && flag_branch_probabilities) cover_insns = PARAM_VALUE (TRACER_DYNAMIC_COVERAGE_FEEDBACK); else cover_insns = PARAM_VALUE (TRACER_DYNAMIC_COVERAGE); cover_insns = (weighted_insns * cover_insns + 50) / 100; max_dup_insns = (ninsns * PARAM_VALUE (TRACER_MAX_CODE_GROWTH) + 50) / 100; while (traced_insns < cover_insns && nduplicated < max_dup_insns && !fibheap_empty (heap)) { basic_block bb = fibheap_extract_min (heap); int n, pos; if (!bb) break; blocks[bb->index] = NULL; if (ignore_bb_p (bb)) continue; gcc_assert (!seen (bb)); n = find_trace (bb, trace); bb = trace[0]; traced_insns += bb->frequency * counts [bb->index]; if (blocks[bb->index]) { fibheap_delete_node (heap, blocks[bb->index]); blocks[bb->index] = NULL; } for (pos = 1; pos < n; pos++) { basic_block bb2 = trace[pos]; if (blocks[bb2->index]) { fibheap_delete_node (heap, blocks[bb2->index]); blocks[bb2->index] = NULL; } traced_insns += bb2->frequency * counts [bb2->index]; if (EDGE_COUNT (bb2->preds) > 1 && can_duplicate_block_p (bb2)) { edge e; basic_block old = bb2; e = find_edge (bb, bb2); nduplicated += counts [bb2->index]; bb2 = duplicate_block (bb2, e, bb); /* Reconsider the original copy of block we've duplicated. Removing the most common predecessor may make it to be head. */ blocks[old->index] = fibheap_insert (heap, -old->frequency, old); if (dump_file) fprintf (dump_file, "Duplicated %i as %i [%i]\n", old->index, bb2->index, bb2->frequency); } bb->aux = bb2; bb2->il.rtl->visited = 1; bb = bb2; /* In case the trace became infrequent, stop duplicating. */ if (ignore_bb_p (bb)) break; } if (dump_file) fprintf (dump_file, " covered now %.1f\n\n", traced_insns * 100.0 / weighted_insns); } if (dump_file) fprintf (dump_file, "Duplicated %i insns (%i%%)\n", nduplicated, nduplicated * 100 / ninsns); free (blocks); free (trace); free (counts); fibheap_delete (heap); }