/* Splits superblocks. */ static void break_superblocks (void) { sbitmap superblocks; int i, need; superblocks = sbitmap_alloc (n_basic_blocks); sbitmap_zero (superblocks); need = 0; for (i = 0; i < n_basic_blocks; i++) if (BASIC_BLOCK(i)->flags & BB_SUPERBLOCK) { BASIC_BLOCK(i)->flags &= ~BB_SUPERBLOCK; SET_BIT (superblocks, i); need = 1; } if (need) { rebuild_jump_labels (get_insns ()); find_many_sub_basic_blocks (superblocks); } free (superblocks); }
/* Splits superblocks. */ void break_superblocks (void) { sbitmap superblocks; bool need = false; basic_block bb; superblocks = sbitmap_alloc (last_basic_block); sbitmap_zero (superblocks); FOR_EACH_BB (bb) if (bb->flags & BB_SUPERBLOCK) { bb->flags &= ~BB_SUPERBLOCK; SET_BIT (superblocks, bb->index); need = true; } if (need) { rebuild_jump_labels (get_insns ()); find_many_sub_basic_blocks (superblocks); } free (superblocks); }
static bool reachable_at_most_once (basic_block va_arg_bb, basic_block va_start_bb) { VEC (edge, heap) *stack = NULL; edge e; edge_iterator ei; sbitmap visited; bool ret; if (va_arg_bb == va_start_bb) return true; if (! dominated_by_p (CDI_DOMINATORS, va_arg_bb, va_start_bb)) return false; visited = sbitmap_alloc (last_basic_block); sbitmap_zero (visited); ret = true; FOR_EACH_EDGE (e, ei, va_arg_bb->preds) VEC_safe_push (edge, heap, stack, e); while (! VEC_empty (edge, stack)) { basic_block src; e = VEC_pop (edge, stack); src = e->src; if (e->flags & EDGE_COMPLEX) { ret = false; break; } if (src == va_start_bb) continue; /* va_arg_bb can be executed more times than va_start_bb. */ if (src == va_arg_bb) { ret = false; break; } gcc_assert (src != ENTRY_BLOCK_PTR); if (! TEST_BIT (visited, src->index)) { SET_BIT (visited, src->index); FOR_EACH_EDGE (e, ei, src->preds) VEC_safe_push (edge, heap, stack, e); } } VEC_free (edge, heap, stack); sbitmap_free (visited); return ret; }
basic_block * blocks_in_phiopt_order (void) { basic_block x, y; basic_block *order = XNEWVEC (basic_block, n_basic_blocks); unsigned n = n_basic_blocks - NUM_FIXED_BLOCKS; unsigned np, i; sbitmap visited = sbitmap_alloc (last_basic_block); #define MARK_VISITED(BB) (SET_BIT (visited, (BB)->index)) #define VISITED_P(BB) (TEST_BIT (visited, (BB)->index)) sbitmap_zero (visited); MARK_VISITED (ENTRY_BLOCK_PTR); FOR_EACH_BB (x) { if (VISITED_P (x)) continue; /* Walk the predecessors of x as long as they have precisely one predecessor and add them to the list, so that they get stored after x. */ for (y = x, np = 1; single_pred_p (y) && !VISITED_P (single_pred (y)); y = single_pred (y)) np++; for (y = x, i = n - np; single_pred_p (y) && !VISITED_P (single_pred (y)); y = single_pred (y), i++) { order[i] = y; MARK_VISITED (y); } order[i] = y; MARK_VISITED (y); gcc_assert (i == n - 1); n -= np; } sbitmap_free (visited); gcc_assert (n == 0); return order; #undef MARK_VISITED #undef VISITED_P }
static void dump_copy_of (FILE *file, tree var) { tree val; sbitmap visited; print_generic_expr (file, var, dump_flags); if (TREE_CODE (var) != SSA_NAME) return; visited = sbitmap_alloc (num_ssa_names); sbitmap_zero (visited); SET_BIT (visited, SSA_NAME_VERSION (var)); fprintf (file, " copy-of chain: "); val = var; print_generic_expr (file, val, 0); fprintf (file, " "); while (copy_of[SSA_NAME_VERSION (val)].value) { fprintf (file, "-> "); val = copy_of[SSA_NAME_VERSION (val)].value; print_generic_expr (file, val, 0); fprintf (file, " "); if (TEST_BIT (visited, SSA_NAME_VERSION (val))) break; SET_BIT (visited, SSA_NAME_VERSION (val)); } val = get_copy_of_val (var)->value; if (val == NULL_TREE) fprintf (file, "[UNDEFINED]"); else if (val != var) fprintf (file, "[COPY]"); else fprintf (file, "[NOT A COPY]"); sbitmap_free (visited); }
static void compute_farthest (struct edge_list *edge_list, int n_exprs, sbitmap *st_avout, sbitmap *st_avin, sbitmap *st_antin, sbitmap *kill, sbitmap *farthest) { sbitmap difference, temp_bitmap; int x, num_edges; basic_block pred, succ; num_edges = NUM_EDGES (edge_list); difference = sbitmap_alloc (n_exprs); temp_bitmap = sbitmap_alloc (n_exprs); for (x = 0; x < num_edges; x++) { pred = INDEX_EDGE_PRED_BB (edge_list, x); succ = INDEX_EDGE_SUCC_BB (edge_list, x); if (succ == EXIT_BLOCK_PTR) sbitmap_copy (farthest[x], st_avout[pred->index]); else { if (pred == ENTRY_BLOCK_PTR) sbitmap_zero (farthest[x]); else { sbitmap_difference (difference, st_avout[pred->index], st_antin[succ->index]); sbitmap_not (temp_bitmap, st_avin[succ->index]); sbitmap_a_and_b_or_c (farthest[x], difference, kill[succ->index], temp_bitmap); } } } sbitmap_free (temp_bitmap); sbitmap_free (difference); }
static void compute_antinout_edge (sbitmap *antloc, sbitmap *transp, sbitmap *antin, sbitmap *antout) { basic_block bb; edge e; basic_block *worklist, *qin, *qout, *qend; unsigned int qlen; edge_iterator ei; /* Allocate a worklist array/queue. Entries are only added to the list if they were not already on the list. So the size is bounded by the number of basic blocks. */ qin = qout = worklist = XNEWVEC (basic_block, n_basic_blocks); /* We want a maximal solution, so make an optimistic initialization of ANTIN. */ sbitmap_vector_ones (antin, last_basic_block); /* Put every block on the worklist; this is necessary because of the optimistic initialization of ANTIN above. */ FOR_EACH_BB_REVERSE (bb) { *qin++ = bb; bb->aux = bb; } qin = worklist; qend = &worklist[n_basic_blocks - NUM_FIXED_BLOCKS]; qlen = n_basic_blocks - NUM_FIXED_BLOCKS; /* Mark blocks which are predecessors of the exit block so that we can easily identify them below. */ FOR_EACH_EDGE (e, ei, EXIT_BLOCK_PTR->preds) e->src->aux = EXIT_BLOCK_PTR; /* Iterate until the worklist is empty. */ while (qlen) { /* Take the first entry off the worklist. */ bb = *qout++; qlen--; if (qout >= qend) qout = worklist; if (bb->aux == EXIT_BLOCK_PTR) /* Do not clear the aux field for blocks which are predecessors of the EXIT block. That way we never add then to the worklist again. */ sbitmap_zero (antout[bb->index]); else { /* Clear the aux field of this block so that it can be added to the worklist again if necessary. */ bb->aux = NULL; sbitmap_intersection_of_succs (antout[bb->index], antin, bb->index); } if (sbitmap_a_or_b_and_c_cg (antin[bb->index], antloc[bb->index], transp[bb->index], antout[bb->index])) /* If the in state of this block changed, then we need to add the predecessors of this block to the worklist if they are not already on the worklist. */ FOR_EACH_EDGE (e, ei, bb->preds) if (!e->src->aux && e->src != ENTRY_BLOCK_PTR) { *qin++ = e->src; e->src->aux = e; qlen++; if (qin >= qend) qin = worklist; } } clear_aux_for_edges (); clear_aux_for_blocks (); free (worklist); }
void compute_available (sbitmap *avloc, sbitmap *kill, sbitmap *avout, sbitmap *avin) { edge e; basic_block *worklist, *qin, *qout, *qend, bb; unsigned int qlen; edge_iterator ei; /* Allocate a worklist array/queue. Entries are only added to the list if they were not already on the list. So the size is bounded by the number of basic blocks. */ qin = qout = worklist = XNEWVEC (basic_block, n_basic_blocks - NUM_FIXED_BLOCKS); /* We want a maximal solution. */ sbitmap_vector_ones (avout, last_basic_block); /* Put every block on the worklist; this is necessary because of the optimistic initialization of AVOUT above. */ FOR_EACH_BB (bb) { *qin++ = bb; bb->aux = bb; } qin = worklist; qend = &worklist[n_basic_blocks - NUM_FIXED_BLOCKS]; qlen = n_basic_blocks - NUM_FIXED_BLOCKS; /* Mark blocks which are successors of the entry block so that we can easily identify them below. */ FOR_EACH_EDGE (e, ei, ENTRY_BLOCK_PTR->succs) e->dest->aux = ENTRY_BLOCK_PTR; /* Iterate until the worklist is empty. */ while (qlen) { /* Take the first entry off the worklist. */ bb = *qout++; qlen--; if (qout >= qend) qout = worklist; /* If one of the predecessor blocks is the ENTRY block, then the intersection of avouts is the null set. We can identify such blocks by the special value in the AUX field in the block structure. */ if (bb->aux == ENTRY_BLOCK_PTR) /* Do not clear the aux field for blocks which are successors of the ENTRY block. That way we never add then to the worklist again. */ sbitmap_zero (avin[bb->index]); else { /* Clear the aux field of this block so that it can be added to the worklist again if necessary. */ bb->aux = NULL; sbitmap_intersection_of_preds (avin[bb->index], avout, bb->index); } if (sbitmap_union_of_diff_cg (avout[bb->index], avloc[bb->index], avin[bb->index], kill[bb->index])) /* If the out state of this block changed, then we need to add the successors of this block to the worklist if they are not already on the worklist. */ FOR_EACH_EDGE (e, ei, bb->succs) if (!e->dest->aux && e->dest != EXIT_BLOCK_PTR) { *qin++ = e->dest; e->dest->aux = e; qlen++; if (qin >= qend) qin = worklist; } } clear_aux_for_edges (); clear_aux_for_blocks (); free (worklist); }
int flow_loops_find (struct loops *loops, int flags) { int i; int b; int num_loops; edge e; sbitmap headers; int *dfs_order; int *rc_order; basic_block header; basic_block bb; /* This function cannot be repeatedly called with different flags to build up the loop information. The loop tree must always be built if this function is called. */ if (! (flags & LOOP_TREE)) abort (); memset (loops, 0, sizeof *loops); /* Taking care of this degenerate case makes the rest of this code simpler. */ if (n_basic_blocks == 0) return 0; dfs_order = NULL; rc_order = NULL; /* Join loops with shared headers. */ canonicalize_loop_headers (); /* Compute the dominators. */ calculate_dominance_info (CDI_DOMINATORS); /* Count the number of loop headers. This should be the same as the number of natural loops. */ headers = sbitmap_alloc (last_basic_block); sbitmap_zero (headers); num_loops = 0; FOR_EACH_BB (header) { int more_latches = 0; header->loop_depth = 0; /* If we have an abnormal predecessor, do not consider the loop (not worth the problems). */ for (e = header->pred; e; e = e->pred_next) if (e->flags & EDGE_ABNORMAL) break; if (e) continue; for (e = header->pred; e; e = e->pred_next) { basic_block latch = e->src; if (e->flags & EDGE_ABNORMAL) abort (); /* Look for back edges where a predecessor is dominated by this block. A natural loop has a single entry node (header) that dominates all the nodes in the loop. It also has single back edge to the header from a latch node. */ if (latch != ENTRY_BLOCK_PTR && dominated_by_p (CDI_DOMINATORS, latch, header)) { /* Shared headers should be eliminated by now. */ if (more_latches) abort (); more_latches = 1; SET_BIT (headers, header->index); num_loops++; } } } /* Allocate loop structures. */ loops->parray = xcalloc (num_loops + 1, sizeof (struct loop *)); /* Dummy loop containing whole function. */ loops->parray[0] = xcalloc (1, sizeof (struct loop)); loops->parray[0]->next = NULL; loops->parray[0]->inner = NULL; loops->parray[0]->outer = NULL; loops->parray[0]->depth = 0; loops->parray[0]->pred = NULL; loops->parray[0]->num_nodes = n_basic_blocks + 2; loops->parray[0]->latch = EXIT_BLOCK_PTR; loops->parray[0]->header = ENTRY_BLOCK_PTR; ENTRY_BLOCK_PTR->loop_father = loops->parray[0]; EXIT_BLOCK_PTR->loop_father = loops->parray[0]; loops->tree_root = loops->parray[0]; /* Find and record information about all the natural loops in the CFG. */ loops->num = 1; FOR_EACH_BB (bb) bb->loop_father = loops->tree_root; if (num_loops) { /* Compute depth first search order of the CFG so that outer natural loops will be found before inner natural loops. */ dfs_order = xmalloc (n_basic_blocks * sizeof (int)); rc_order = xmalloc (n_basic_blocks * sizeof (int)); flow_depth_first_order_compute (dfs_order, rc_order); /* Save CFG derived information to avoid recomputing it. */ loops->cfg.dfs_order = dfs_order; loops->cfg.rc_order = rc_order; num_loops = 1; for (b = 0; b < n_basic_blocks; b++) { struct loop *loop; /* Search the nodes of the CFG in reverse completion order so that we can find outer loops first. */ if (!TEST_BIT (headers, rc_order[b])) continue; header = BASIC_BLOCK (rc_order[b]); loop = loops->parray[num_loops] = xcalloc (1, sizeof (struct loop)); loop->header = header; loop->num = num_loops; num_loops++; /* Look for the latch for this header block. */ for (e = header->pred; e; e = e->pred_next) { basic_block latch = e->src; if (latch != ENTRY_BLOCK_PTR && dominated_by_p (CDI_DOMINATORS, latch, header)) { loop->latch = latch; break; } } flow_loop_tree_node_add (header->loop_father, loop); loop->num_nodes = flow_loop_nodes_find (loop->header, loop); } /* Assign the loop nesting depth and enclosed loop level for each loop. */ loops->levels = flow_loops_level_compute (loops); /* Scan the loops. */ for (i = 1; i < num_loops; i++) flow_loop_scan (loops->parray[i], flags); loops->num = num_loops; } else { free_dominance_info (CDI_DOMINATORS); } sbitmap_free (headers); loops->state = 0; #ifdef ENABLE_CHECKING verify_flow_info (); verify_loop_structure (loops); #endif return loops->num; }
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; /* Create an oversized sbitmap to reduce the chance that we need to resize it. */ bb_seen = sbitmap_alloc (last_basic_block * 2); sbitmap_zero (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)) { 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; } 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); }
static struct loop * unswitch_loop (struct loops *loops, struct loop *loop, basic_block unswitch_on, rtx cond, rtx cinsn) { edge entry, latch_edge, true_edge, false_edge, e; basic_block switch_bb, unswitch_on_alt; struct loop *nloop; sbitmap zero_bitmap; int irred_flag, prob; rtx seq; /* Some sanity checking. */ gcc_assert (flow_bb_inside_loop_p (loop, unswitch_on)); gcc_assert (EDGE_COUNT (unswitch_on->succs) == 2); gcc_assert (just_once_each_iteration_p (loop, unswitch_on)); gcc_assert (!loop->inner); gcc_assert (flow_bb_inside_loop_p (loop, EDGE_SUCC (unswitch_on, 0)->dest)); gcc_assert (flow_bb_inside_loop_p (loop, EDGE_SUCC (unswitch_on, 1)->dest)); entry = loop_preheader_edge (loop); /* Make a copy. */ irred_flag = entry->flags & EDGE_IRREDUCIBLE_LOOP; entry->flags &= ~EDGE_IRREDUCIBLE_LOOP; zero_bitmap = sbitmap_alloc (2); sbitmap_zero (zero_bitmap); if (!duplicate_loop_to_header_edge (loop, entry, loops, 1, zero_bitmap, NULL, NULL, NULL, 0)) { sbitmap_free (zero_bitmap); return NULL; } sbitmap_free (zero_bitmap); entry->flags |= irred_flag; /* Record the block with condition we unswitch on. */ unswitch_on_alt = get_bb_copy (unswitch_on); true_edge = BRANCH_EDGE (unswitch_on_alt); false_edge = FALLTHRU_EDGE (unswitch_on); latch_edge = single_succ_edge (get_bb_copy (loop->latch)); /* Create a block with the condition. */ prob = true_edge->probability; switch_bb = create_empty_bb (EXIT_BLOCK_PTR->prev_bb); seq = compare_and_jump_seq (XEXP (cond, 0), XEXP (cond, 1), GET_CODE (cond), block_label (true_edge->dest), prob, cinsn); emit_insn_after (seq, BB_END (switch_bb)); e = make_edge (switch_bb, true_edge->dest, 0); e->probability = prob; e->count = latch_edge->count * prob / REG_BR_PROB_BASE; e = make_edge (switch_bb, FALLTHRU_EDGE (unswitch_on)->dest, EDGE_FALLTHRU); e->probability = false_edge->probability; e->count = latch_edge->count * (false_edge->probability) / REG_BR_PROB_BASE; if (irred_flag) { switch_bb->flags |= BB_IRREDUCIBLE_LOOP; EDGE_SUCC (switch_bb, 0)->flags |= EDGE_IRREDUCIBLE_LOOP; EDGE_SUCC (switch_bb, 1)->flags |= EDGE_IRREDUCIBLE_LOOP; } else { switch_bb->flags &= ~BB_IRREDUCIBLE_LOOP; EDGE_SUCC (switch_bb, 0)->flags &= ~EDGE_IRREDUCIBLE_LOOP; EDGE_SUCC (switch_bb, 1)->flags &= ~EDGE_IRREDUCIBLE_LOOP; } /* Loopify from the copy of LOOP body, constructing the new loop. */ nloop = loopify (loops, latch_edge, single_pred_edge (get_bb_copy (loop->header)), switch_bb, BRANCH_EDGE (switch_bb), FALLTHRU_EDGE (switch_bb), true); /* Remove branches that are now unreachable in new loops. */ remove_path (loops, true_edge); remove_path (loops, false_edge); /* One of created loops do not have to be subloop of the outer loop now, so fix its placement in loop data structure. */ fix_loop_placement (loop); fix_loop_placement (nloop); /* Preserve the simple loop preheaders. */ loop_split_edge_with (loop_preheader_edge (loop), NULL_RTX); loop_split_edge_with (loop_preheader_edge (nloop), NULL_RTX); return nloop; }
static unsigned int copyprop_hardreg_forward (void) { struct value_data *all_vd; basic_block bb; sbitmap visited; bool analyze_called = false; all_vd = XNEWVEC (struct value_data, last_basic_block); visited = sbitmap_alloc (last_basic_block); sbitmap_zero (visited); if (MAY_HAVE_DEBUG_INSNS) debug_insn_changes_pool = create_alloc_pool ("debug insn changes pool", sizeof (struct queued_debug_insn_change), 256); FOR_EACH_BB (bb) { SET_BIT (visited, bb->index); /* If a block has a single predecessor, that we've already processed, begin with the value data that was live at the end of the predecessor block. */ /* ??? Ought to use more intelligent queuing of blocks. */ if (single_pred_p (bb) && TEST_BIT (visited, single_pred (bb)->index) && ! (single_pred_edge (bb)->flags & (EDGE_ABNORMAL_CALL | EDGE_EH))) { all_vd[bb->index] = all_vd[single_pred (bb)->index]; if (all_vd[bb->index].n_debug_insn_changes) { unsigned int regno; for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++) { if (all_vd[bb->index].e[regno].debug_insn_changes) { all_vd[bb->index].e[regno].debug_insn_changes = NULL; if (--all_vd[bb->index].n_debug_insn_changes == 0) break; } } } } else init_value_data (all_vd + bb->index); copyprop_hardreg_forward_1 (bb, all_vd + bb->index); } if (MAY_HAVE_DEBUG_INSNS) { FOR_EACH_BB (bb) if (TEST_BIT (visited, bb->index) && all_vd[bb->index].n_debug_insn_changes) { unsigned int regno; bitmap live; if (!analyze_called) { df_analyze (); analyze_called = true; } live = df_get_live_out (bb); for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++) if (all_vd[bb->index].e[regno].debug_insn_changes) { if (REGNO_REG_SET_P (live, regno)) apply_debug_insn_changes (all_vd + bb->index, regno); if (all_vd[bb->index].n_debug_insn_changes == 0) break; } } free_alloc_pool (debug_insn_changes_pool); } sbitmap_free (visited); free (all_vd); return 0; }