void alloc_aux_for_edges (int size) { static int initialized; if (!initialized) { gcc_obstack_init (&edge_aux_obstack); initialized = 1; } else /* Check whether AUX data are still allocated. */ gcc_assert (!first_edge_aux_obj); first_edge_aux_obj = obstack_alloc (&edge_aux_obstack, 0); if (size) { basic_block bb; FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR, EXIT_BLOCK_PTR, next_bb) { edge e; edge_iterator ei; FOR_EACH_EDGE (e, ei, bb->succs) alloc_aux_for_edge (e, size); } }
/* Redirect edge and update latch and header info. */ static void redirect_edge_with_latch_update (edge e, basic_block to) { basic_block jump; jump = redirect_edge_and_branch_force (e, to); if (jump) { alloc_aux_for_block (jump, sizeof (int)); HEADER_BLOCK (jump) = 0; alloc_aux_for_edge (jump->pred, sizeof (int)); LATCH_EDGE (jump->succ) = LATCH_EDGE (e); LATCH_EDGE (jump->pred) = 0; } }
static basic_block make_forwarder_block (basic_block bb, int redirect_latch, int redirect_nonlatch, edge except, int conn_latch) { edge e, next_e, fallthru; basic_block dummy; rtx insn; insn = PREV_INSN (first_insn_after_basic_block_note (bb)); /* For empty block split_block will return NULL. */ if (BB_END (bb) == insn) emit_note_after (NOTE_INSN_DELETED, insn); fallthru = split_block (bb, insn); dummy = fallthru->src; bb = fallthru->dest; bb->aux = xmalloc (sizeof (int)); HEADER_BLOCK (dummy) = 0; HEADER_BLOCK (bb) = 1; /* Redirect back edges we want to keep. */ for (e = dummy->pred; e; e = next_e) { next_e = e->pred_next; if (e == except || !((redirect_latch && LATCH_EDGE (e)) || (redirect_nonlatch && !LATCH_EDGE (e)))) { dummy->frequency -= EDGE_FREQUENCY (e); dummy->count -= e->count; if (dummy->frequency < 0) dummy->frequency = 0; if (dummy->count < 0) dummy->count = 0; redirect_edge_with_latch_update (e, bb); } } alloc_aux_for_edge (fallthru, sizeof (int)); LATCH_EDGE (fallthru) = conn_latch; return dummy; }
/* Takes care of merging natural loops with shared headers. */ static void canonicalize_loop_headers (void) { basic_block header; edge e; /* Compute the dominators. */ calculate_dominance_info (CDI_DOMINATORS); alloc_aux_for_blocks (sizeof (int)); alloc_aux_for_edges (sizeof (int)); /* Split blocks so that each loop has only single latch. */ FOR_EACH_BB (header) { int num_latches = 0; int have_abnormal_edge = 0; for (e = header->pred; e; e = e->pred_next) { basic_block latch = e->src; if (e->flags & EDGE_ABNORMAL) have_abnormal_edge = 1; if (latch != ENTRY_BLOCK_PTR && dominated_by_p (CDI_DOMINATORS, latch, header)) { num_latches++; LATCH_EDGE (e) = 1; } } if (have_abnormal_edge) HEADER_BLOCK (header) = 0; else HEADER_BLOCK (header) = num_latches; } free_dominance_info (CDI_DOMINATORS); if (HEADER_BLOCK (ENTRY_BLOCK_PTR->succ->dest)) { basic_block bb; /* We could not redirect edges freely here. On the other hand, we can simply split the edge from entry block. */ bb = split_edge (ENTRY_BLOCK_PTR->succ); alloc_aux_for_edge (bb->succ, sizeof (int)); LATCH_EDGE (bb->succ) = 0; alloc_aux_for_block (bb, sizeof (int)); HEADER_BLOCK (bb) = 0; } FOR_EACH_BB (header) { int num_latch; int want_join_latch; int max_freq, is_heavy; edge heavy; if (!HEADER_BLOCK (header)) continue; num_latch = HEADER_BLOCK (header); want_join_latch = (num_latch > 1); if (!want_join_latch) continue; /* Find a heavy edge. */ is_heavy = 1; heavy = NULL; max_freq = 0; for (e = header->pred; e; e = e->pred_next) if (LATCH_EDGE (e) && EDGE_FREQUENCY (e) > max_freq) max_freq = EDGE_FREQUENCY (e); for (e = header->pred; e; e = e->pred_next) if (LATCH_EDGE (e) && EDGE_FREQUENCY (e) >= max_freq / HEAVY_EDGE_RATIO) { if (heavy) { is_heavy = 0; break; } else heavy = e; } if (is_heavy) { basic_block new_header = make_forwarder_block (header, true, true, heavy, 0); if (num_latch > 2) make_forwarder_block (new_header, true, false, NULL, 1); } else make_forwarder_block (header, true, false, NULL, 1); } free_aux_for_blocks (); free_aux_for_edges (); }