static basic_block copy_bb (basic_block old_bb, edge e, basic_block bb, int trace) { basic_block new_bb; new_bb = cfg_layout_duplicate_bb (old_bb, e); if (e->dest != new_bb) abort (); if (e->dest->rbi->visited) abort (); if (rtl_dump_file) fprintf (rtl_dump_file, "Duplicated bb %d (created bb %d)\n", old_bb->index, new_bb->index); new_bb->rbi->visited = trace; new_bb->rbi->next = bb->rbi->next; bb->rbi->next = new_bb; if (new_bb->index >= array_size || last_basic_block > array_size) { int i; int new_size; new_size = MAX (last_basic_block, new_bb->index + 1); new_size = GET_ARRAY_SIZE (new_size); bbd = xrealloc (bbd, new_size * sizeof (bbro_basic_block_data)); for (i = array_size; i < new_size; i++) { bbd[i].start_of_trace = -1; bbd[i].end_of_trace = -1; bbd[i].heap = NULL; bbd[i].node = NULL; } array_size = new_size; if (rtl_dump_file) { fprintf (rtl_dump_file, "Growing the dynamic array to %d elements.\n", array_size); } } return new_bb; }
void copy_bbs (basic_block *bbs, unsigned n, basic_block *new_bbs, edge *edges, unsigned n_edges, edge *new_edges, struct loop *base) { unsigned i, j; basic_block bb, new_bb, dom_bb; edge e; /* Duplicate bbs, update dominators, assign bbs to loops. */ for (i = 0; i < n; i++) { /* Duplicate. */ bb = bbs[i]; new_bb = new_bbs[i] = cfg_layout_duplicate_bb (bb, NULL); bb->rbi->duplicated = 1; /* Add to loop. */ add_bb_to_loop (new_bb, bb->loop_father->copy); add_to_dominance_info (CDI_DOMINATORS, new_bb); /* Possibly set header. */ if (bb->loop_father->header == bb && bb->loop_father != base) new_bb->loop_father->header = new_bb; /* Or latch. */ if (bb->loop_father->latch == bb && bb->loop_father != base) new_bb->loop_father->latch = new_bb; } /* Set dominators. */ for (i = 0; i < n; i++) { bb = bbs[i]; new_bb = new_bbs[i]; dom_bb = get_immediate_dominator (CDI_DOMINATORS, bb); if (dom_bb->rbi->duplicated) { dom_bb = dom_bb->rbi->copy; set_immediate_dominator (CDI_DOMINATORS, new_bb, dom_bb); } } /* Redirect edges. */ for (j = 0; j < n_edges; j++) new_edges[j] = NULL; for (i = 0; i < n; i++) { new_bb = new_bbs[i]; bb = bbs[i]; for (e = new_bb->succ; e; e = e->succ_next) { for (j = 0; j < n_edges; j++) if (edges[j] && edges[j]->src == bb && edges[j]->dest == e->dest) new_edges[j] = e; if (!e->dest->rbi->duplicated) continue; redirect_edge_and_branch_force (e, e->dest->rbi->copy); } } /* Clear information about duplicates. */ for (i = 0; i < n; i++) bbs[i]->rbi->duplicated = 0; }
static void tail_duplicate (void) { fibnode_t *blocks = xcalloc (last_basic_block, sizeof (fibnode_t)); basic_block *trace = xmalloc (sizeof (basic_block) * n_basic_blocks); int *counts = xmalloc (sizeof (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; if (seen (bb)) abort (); 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 (bb2->pred && bb2->pred->pred_next && cfg_layout_can_duplicate_bb_p (bb2)) { edge e = bb2->pred; basic_block old = bb2; while (e->src != bb) e = e->pred_next; nduplicated += counts [bb2->index]; bb2 = cfg_layout_duplicate_bb (bb2, e); /* 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 (rtl_dump_file) fprintf (rtl_dump_file, "Duplicated %i as %i [%i]\n", old->index, bb2->index, bb2->frequency); } bb->rbi->next = bb2; bb2->rbi->visited = 1; bb = bb2; /* In case the trace became infrequent, stop duplicating. */ if (ignore_bb_p (bb)) break; } if (rtl_dump_file) fprintf (rtl_dump_file, " covered now %.1f\n\n", traced_insns * 100.0 / weighted_insns); } if (rtl_dump_file) fprintf (rtl_dump_file, "Duplicated %i insns (%i%%)\n", nduplicated, nduplicated * 100 / ninsns); free (blocks); free (trace); free (counts); fibheap_delete (heap); }