VOID copy_spec(LONG tree, WORD obj) { WORD type; LONG obspec; type = LLOBT(GET_TYPE(tree, obj)); obspec = GET_SPEC(tree, obj); switch (type) { case G_TEXT: case G_BOXTEXT: case G_FTEXT: case G_FBOXTEXT: obspec = copy_ti(obspec); break; case G_ICON: obspec = copy_ib(obspec); break; case G_IMAGE: obspec = copy_bb(obspec); break; default: return; } SET_SPEC(tree, obj, obspec); }
static void find_traces_1_round (int branch_th, int exec_th, gcov_type count_th, struct trace *traces, int *n_traces, int round, fibheap_t *heap) { /* Heap for discarded basic blocks which are possible starting points for the next round. */ fibheap_t new_heap = fibheap_new (); while (!fibheap_empty (*heap)) { basic_block bb; struct trace *trace; edge best_edge, e; fibheapkey_t key; bb = fibheap_extract_min (*heap); bbd[bb->index].heap = NULL; bbd[bb->index].node = NULL; if (rtl_dump_file) fprintf (rtl_dump_file, "Getting bb %d\n", bb->index); /* If the BB's frequency is too low send BB to the next round. */ if (round < N_ROUNDS - 1 && (bb->frequency < exec_th || bb->count < count_th || probably_never_executed_bb_p (bb))) { int key = bb_to_key (bb); bbd[bb->index].heap = new_heap; bbd[bb->index].node = fibheap_insert (new_heap, key, bb); if (rtl_dump_file) fprintf (rtl_dump_file, " Possible start point of next round: %d (key: %d)\n", bb->index, key); continue; } trace = traces + *n_traces; trace->first = bb; trace->round = round; trace->length = 0; (*n_traces)++; do { int prob, freq; /* The probability and frequency of the best edge. */ int best_prob = INT_MIN / 2; int best_freq = INT_MIN / 2; best_edge = NULL; mark_bb_visited (bb, *n_traces); trace->length++; if (rtl_dump_file) fprintf (rtl_dump_file, "Basic block %d was visited in trace %d\n", bb->index, *n_traces - 1); /* Select the successor that will be placed after BB. */ for (e = bb->succ; e; e = e->succ_next) { #ifdef ENABLE_CHECKING if (e->flags & EDGE_FAKE) abort (); #endif if (e->dest == EXIT_BLOCK_PTR) continue; if (e->dest->rbi->visited && e->dest->rbi->visited != *n_traces) continue; prob = e->probability; freq = EDGE_FREQUENCY (e); /* Edge that cannot be fallthru or improbable or infrequent successor (ie. it is unsuitable successor). */ if (!(e->flags & EDGE_CAN_FALLTHRU) || (e->flags & EDGE_COMPLEX) || prob < branch_th || freq < exec_th || e->count < count_th) continue; if (better_edge_p (bb, e, prob, freq, best_prob, best_freq)) { best_edge = e; best_prob = prob; best_freq = freq; } } /* If the best destination has multiple predecessors, and can be duplicated cheaper than a jump, don't allow it to be added to a trace. We'll duplicate it when connecting traces. */ if (best_edge && best_edge->dest->pred->pred_next && copy_bb_p (best_edge->dest, 0)) best_edge = NULL; /* Add all non-selected successors to the heaps. */ for (e = bb->succ; e; e = e->succ_next) { if (e == best_edge || e->dest == EXIT_BLOCK_PTR || e->dest->rbi->visited) continue; key = bb_to_key (e->dest); if (bbd[e->dest->index].heap) { /* E->DEST is already in some heap. */ if (key != bbd[e->dest->index].node->key) { if (rtl_dump_file) { fprintf (rtl_dump_file, "Changing key for bb %d from %ld to %ld.\n", e->dest->index, (long) bbd[e->dest->index].node->key, key); } fibheap_replace_key (bbd[e->dest->index].heap, bbd[e->dest->index].node, key); } } else { fibheap_t which_heap = *heap; prob = e->probability; freq = EDGE_FREQUENCY (e); if (!(e->flags & EDGE_CAN_FALLTHRU) || (e->flags & EDGE_COMPLEX) || prob < branch_th || freq < exec_th || e->count < count_th) { if (round < N_ROUNDS - 1) which_heap = new_heap; } bbd[e->dest->index].heap = which_heap; bbd[e->dest->index].node = fibheap_insert (which_heap, key, e->dest); if (rtl_dump_file) { fprintf (rtl_dump_file, " Possible start of %s round: %d (key: %ld)\n", (which_heap == new_heap) ? "next" : "this", e->dest->index, (long) key); } } } if (best_edge) /* Suitable successor was found. */ { if (best_edge->dest->rbi->visited == *n_traces) { /* We do nothing with one basic block loops. */ if (best_edge->dest != bb) { if (EDGE_FREQUENCY (best_edge) > 4 * best_edge->dest->frequency / 5) { /* The loop has at least 4 iterations. If the loop header is not the first block of the function we can rotate the loop. */ if (best_edge->dest != ENTRY_BLOCK_PTR->next_bb) { if (rtl_dump_file) { fprintf (rtl_dump_file, "Rotating loop %d - %d\n", best_edge->dest->index, bb->index); } bb->rbi->next = best_edge->dest; bb = rotate_loop (best_edge, trace, *n_traces); } } else { /* The loop has less than 4 iterations. */ /* Check whether there is another edge from BB. */ edge another_edge; for (another_edge = bb->succ; another_edge; another_edge = another_edge->succ_next) if (another_edge != best_edge) break; if (!another_edge && copy_bb_p (best_edge->dest, !optimize_size)) { bb = copy_bb (best_edge->dest, best_edge, bb, *n_traces); } } } /* Terminate the trace. */ break; } else { /* Check for a situation A /| B | \| C where EDGE_FREQUENCY (AB) + EDGE_FREQUENCY (BC) >= EDGE_FREQUENCY (AC). (i.e. 2 * B->frequency >= EDGE_FREQUENCY (AC) ) Best ordering is then A B C. This situation is created for example by: if (A) B; C; */ for (e = bb->succ; e; e = e->succ_next) if (e != best_edge && (e->flags & EDGE_CAN_FALLTHRU) && !(e->flags & EDGE_COMPLEX) && !e->dest->rbi->visited && !e->dest->pred->pred_next && e->dest->succ && (e->dest->succ->flags & EDGE_CAN_FALLTHRU) && !(e->dest->succ->flags & EDGE_COMPLEX) && !e->dest->succ->succ_next && e->dest->succ->dest == best_edge->dest && 2 * e->dest->frequency >= EDGE_FREQUENCY (best_edge)) { best_edge = e; if (rtl_dump_file) fprintf (rtl_dump_file, "Selecting BB %d\n", best_edge->dest->index); break; } bb->rbi->next = best_edge->dest; bb = best_edge->dest; } } } while (best_edge); trace->last = bb; bbd[trace->first->index].start_of_trace = *n_traces - 1; bbd[trace->last->index].end_of_trace = *n_traces - 1; /* The trace is terminated so we have to recount the keys in heap (some block can have a lower key because now one of its predecessors is an end of the trace). */ for (e = bb->succ; e; e = e->succ_next) { if (e->dest == EXIT_BLOCK_PTR || e->dest->rbi->visited) continue; if (bbd[e->dest->index].heap) { key = bb_to_key (e->dest); if (key != bbd[e->dest->index].node->key) { if (rtl_dump_file) { fprintf (rtl_dump_file, "Changing key for bb %d from %ld to %ld.\n", e->dest->index, (long) bbd[e->dest->index].node->key, key); } fibheap_replace_key (bbd[e->dest->index].heap, bbd[e->dest->index].node, key); } } } } fibheap_delete (*heap); /* "Return" the new heap. */ *heap = new_heap; }
static void connect_traces (int n_traces, struct trace *traces) { int i; bool *connected; int last_trace; int freq_threshold; gcov_type count_threshold; freq_threshold = max_entry_frequency * DUPLICATION_THRESHOLD / 1000; if (max_entry_count < INT_MAX / 1000) count_threshold = max_entry_count * DUPLICATION_THRESHOLD / 1000; else count_threshold = max_entry_count / 1000 * DUPLICATION_THRESHOLD; connected = xcalloc (n_traces, sizeof (bool)); last_trace = -1; for (i = 0; i < n_traces; i++) { int t = i; int t2; edge e, best; int best_len; if (connected[t]) continue; connected[t] = true; /* Find the predecessor traces. */ for (t2 = t; t2 > 0;) { best = NULL; best_len = 0; for (e = traces[t2].first->pred; e; e = e->pred_next) { int si = e->src->index; if (e->src != ENTRY_BLOCK_PTR && (e->flags & EDGE_CAN_FALLTHRU) && !(e->flags & EDGE_COMPLEX) && bbd[si].end_of_trace >= 0 && !connected[bbd[si].end_of_trace] && (!best || e->probability > best->probability || (e->probability == best->probability && traces[bbd[si].end_of_trace].length > best_len))) { best = e; best_len = traces[bbd[si].end_of_trace].length; } } if (best) { best->src->rbi->next = best->dest; t2 = bbd[best->src->index].end_of_trace; connected[t2] = true; if (rtl_dump_file) { fprintf (rtl_dump_file, "Connection: %d %d\n", best->src->index, best->dest->index); } } else break; } if (last_trace >= 0) traces[last_trace].last->rbi->next = traces[t2].first; last_trace = t; /* Find the successor traces. */ while (1) { /* Find the continuation of the chain. */ best = NULL; best_len = 0; for (e = traces[t].last->succ; e; e = e->succ_next) { int di = e->dest->index; if (e->dest != EXIT_BLOCK_PTR && (e->flags & EDGE_CAN_FALLTHRU) && !(e->flags & EDGE_COMPLEX) && bbd[di].start_of_trace >= 0 && !connected[bbd[di].start_of_trace] && (!best || e->probability > best->probability || (e->probability == best->probability && traces[bbd[di].start_of_trace].length > best_len))) { best = e; best_len = traces[bbd[di].start_of_trace].length; } } if (best) { if (rtl_dump_file) { fprintf (rtl_dump_file, "Connection: %d %d\n", best->src->index, best->dest->index); } t = bbd[best->dest->index].start_of_trace; traces[last_trace].last->rbi->next = traces[t].first; connected[t] = true; last_trace = t; } else { /* Try to connect the traces by duplication of 1 block. */ edge e2; basic_block next_bb = NULL; bool try_copy = false; for (e = traces[t].last->succ; e; e = e->succ_next) if (e->dest != EXIT_BLOCK_PTR && (e->flags & EDGE_CAN_FALLTHRU) && !(e->flags & EDGE_COMPLEX) && (!best || e->probability > best->probability)) { edge best2 = NULL; int best2_len = 0; /* If the destination is a start of a trace which is only one block long, then no need to search the successor blocks of the trace. Accept it. */ if (bbd[e->dest->index].start_of_trace >= 0 && traces[bbd[e->dest->index].start_of_trace].length == 1) { best = e; try_copy = true; continue; } for (e2 = e->dest->succ; e2; e2 = e2->succ_next) { int di = e2->dest->index; if (e2->dest == EXIT_BLOCK_PTR || ((e2->flags & EDGE_CAN_FALLTHRU) && !(e2->flags & EDGE_COMPLEX) && bbd[di].start_of_trace >= 0 && !connected[bbd[di].start_of_trace] && (EDGE_FREQUENCY (e2) >= freq_threshold) && (e2->count >= count_threshold) && (!best2 || e2->probability > best2->probability || (e2->probability == best2->probability && traces[bbd[di].start_of_trace].length > best2_len)))) { best = e; best2 = e2; if (e2->dest != EXIT_BLOCK_PTR) best2_len = traces[bbd[di].start_of_trace].length; else best2_len = INT_MAX; next_bb = e2->dest; try_copy = true; } } } /* Copy tiny blocks always; copy larger blocks only when the edge is traversed frequently enough. */ if (try_copy && copy_bb_p (best->dest, !optimize_size && EDGE_FREQUENCY (best) >= freq_threshold && best->count >= count_threshold)) { basic_block new_bb; if (rtl_dump_file) { fprintf (rtl_dump_file, "Connection: %d %d ", traces[t].last->index, best->dest->index); if (!next_bb) fputc ('\n', rtl_dump_file); else if (next_bb == EXIT_BLOCK_PTR) fprintf (rtl_dump_file, "exit\n"); else fprintf (rtl_dump_file, "%d\n", next_bb->index); } new_bb = copy_bb (best->dest, best, traces[t].last, t); traces[t].last = new_bb; if (next_bb && next_bb != EXIT_BLOCK_PTR) { t = bbd[next_bb->index].start_of_trace; traces[last_trace].last->rbi->next = traces[t].first; connected[t] = true; last_trace = t; } else break; /* Stop finding the successor traces. */ } else break; /* Stop finding the successor traces. */ } } } if (rtl_dump_file) { basic_block bb; fprintf (rtl_dump_file, "Final order:\n"); for (bb = traces[0].first; bb; bb = bb->rbi->next) fprintf (rtl_dump_file, "%d ", bb->index); fprintf (rtl_dump_file, "\n"); fflush (rtl_dump_file); } FREE (connected); }
static basic_block rotate_loop (edge back_edge, struct trace *trace, int trace_n) { basic_block bb; /* Information about the best end (end after rotation) of the loop. */ basic_block best_bb = NULL; edge best_edge = NULL; int best_freq = -1; gcov_type best_count = -1; /* The best edge is preferred when its destination is not visited yet or is a start block of some trace. */ bool is_preferred = false; /* Find the most frequent edge that goes out from current trace. */ bb = back_edge->dest; do { edge e; for (e = bb->succ; e; e = e->succ_next) if (e->dest != EXIT_BLOCK_PTR && e->dest->rbi->visited != trace_n && (e->flags & EDGE_CAN_FALLTHRU) && !(e->flags & EDGE_COMPLEX)) { if (is_preferred) { /* The best edge is preferred. */ if (!e->dest->rbi->visited || bbd[e->dest->index].start_of_trace >= 0) { /* The current edge E is also preferred. */ int freq = EDGE_FREQUENCY (e); if (freq > best_freq || e->count > best_count) { best_freq = freq; best_count = e->count; best_edge = e; best_bb = bb; } } } else { if (!e->dest->rbi->visited || bbd[e->dest->index].start_of_trace >= 0) { /* The current edge E is preferred. */ is_preferred = true; best_freq = EDGE_FREQUENCY (e); best_count = e->count; best_edge = e; best_bb = bb; } else { int freq = EDGE_FREQUENCY (e); if (!best_edge || freq > best_freq || e->count > best_count) { best_freq = freq; best_count = e->count; best_edge = e; best_bb = bb; } } } } bb = bb->rbi->next; } while (bb != back_edge->dest); if (best_bb) { /* Rotate the loop so that the BEST_EDGE goes out from the last block of the trace. */ if (back_edge->dest == trace->first) { trace->first = best_bb->rbi->next; } else { basic_block prev_bb; for (prev_bb = trace->first; prev_bb->rbi->next != back_edge->dest; prev_bb = prev_bb->rbi->next) ; prev_bb->rbi->next = best_bb->rbi->next; /* Try to get rid of uncond jump to cond jump. */ if (prev_bb->succ && !prev_bb->succ->succ_next) { basic_block header = prev_bb->succ->dest; /* Duplicate HEADER if it is a small block containing cond jump in the end. */ if (any_condjump_p (BB_END (header)) && copy_bb_p (header, 0)) { copy_bb (header, prev_bb->succ, prev_bb, trace_n); } } } } else { /* We have not found suitable loop tail so do no rotation. */ best_bb = back_edge->src; } best_bb->rbi->next = NULL; return best_bb; }