+
+/* Checks whether all N blocks in BBS array can be copied. */
+bool
+can_copy_bbs_p (basic_block *bbs, unsigned n)
+{
+ unsigned i;
+ edge e;
+ int ret = true;
+
+ for (i = 0; i < n; i++)
+ bbs[i]->flags |= BB_DUPLICATED;
+
+ for (i = 0; i < n; i++)
+ {
+ /* In case we should redirect abnormal edge during duplication, fail. */
+ edge_iterator ei;
+ FOR_EACH_EDGE (e, ei, bbs[i]->succs)
+ if ((e->flags & EDGE_ABNORMAL)
+ && (e->dest->flags & BB_DUPLICATED))
+ {
+ ret = false;
+ goto end;
+ }
+
+ if (!can_duplicate_block_p (bbs[i]))
+ {
+ ret = false;
+ break;
+ }
+ }
+
+end:
+ for (i = 0; i < n; i++)
+ bbs[i]->flags &= ~BB_DUPLICATED;
+
+ return ret;
+}
+
+/* Duplicates N basic blocks stored in array BBS. Newly created basic blocks
+ are placed into array NEW_BBS in the same order. Edges from basic blocks
+ in BBS are also duplicated and copies of those of them
+ that lead into BBS are redirected to appropriate newly created block. The
+ function assigns bbs into loops (copy of basic block bb is assigned to
+ bb->loop_father->copy loop, so this must be set up correctly in advance)
+ and updates dominators locally (LOOPS structure that contains the information
+ about dominators is passed to enable this).
+
+ BASE is the superloop to that basic block belongs; if its header or latch
+ is copied, we do not set the new blocks as header or latch.
+
+ Created copies of N_EDGES edges in array EDGES are stored in array NEW_EDGES,
+ also in the same order.
+
+ Newly created basic blocks are put after the basic block AFTER in the
+ instruction stream, and the order of the blocks in BBS array is preserved. */
+
+void
+copy_bbs (basic_block *bbs, unsigned n, basic_block *new_bbs,
+ edge *edges, unsigned num_edges, edge *new_edges,
+ struct loop *base, basic_block after)
+{
+ 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] = duplicate_block (bb, NULL, after);
+ after = new_bb;
+ bb->flags |= BB_DUPLICATED;
+ if (bb->loop_father)
+ {
+ /* Possibly set loop 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->flags & BB_DUPLICATED)
+ {
+ dom_bb = get_bb_copy (dom_bb);
+ set_immediate_dominator (CDI_DOMINATORS, new_bb, dom_bb);
+ }
+ }
+
+ /* Redirect edges. */
+ for (j = 0; j < num_edges; j++)
+ new_edges[j] = NULL;
+ for (i = 0; i < n; i++)
+ {
+ edge_iterator ei;
+ new_bb = new_bbs[i];
+ bb = bbs[i];
+
+ FOR_EACH_EDGE (e, ei, new_bb->succs)
+ {
+ for (j = 0; j < num_edges; j++)
+ if (edges[j] && edges[j]->src == bb && edges[j]->dest == e->dest)
+ new_edges[j] = e;
+
+ if (!(e->dest->flags & BB_DUPLICATED))
+ continue;
+ redirect_edge_and_branch_force (e, get_bb_copy (e->dest));
+ }
+ }
+
+ /* Clear information about duplicates. */
+ for (i = 0; i < n; i++)
+ bbs[i]->flags &= ~BB_DUPLICATED;
+}
+
+/* Return true if BB contains only labels or non-executable
+ instructions */
+bool
+empty_block_p (basic_block bb)
+{
+ gcc_assert (cfg_hooks->empty_block_p);
+ return cfg_hooks->empty_block_p (bb);
+}
+
+/* Split a basic block if it ends with a conditional branch and if
+ the other part of the block is not empty. */
+basic_block
+split_block_before_cond_jump (basic_block bb)
+{
+ gcc_assert (cfg_hooks->split_block_before_cond_jump);
+ return cfg_hooks->split_block_before_cond_jump (bb);
+}
+
+/* Work-horse for passes.c:check_profile_consistency.
+ Do book-keeping of the CFG for the profile consistency checker.
+ If AFTER_PASS is 0, do pre-pass accounting, or if AFTER_PASS is 1
+ then do post-pass accounting. Store the counting in RECORD. */
+
+void
+account_profile_record (struct profile_record *record, int after_pass)
+{
+ basic_block bb;
+ edge_iterator ei;
+ edge e;
+ int sum;
+ gcov_type lsum;
+
+ FOR_ALL_BB (bb)
+ {
+ if (bb != EXIT_BLOCK_PTR_FOR_FUNCTION (cfun)
+ && profile_status != PROFILE_ABSENT)
+ {
+ sum = 0;
+ FOR_EACH_EDGE (e, ei, bb->succs)
+ sum += e->probability;
+ if (EDGE_COUNT (bb->succs) && abs (sum - REG_BR_PROB_BASE) > 100)
+ record->num_mismatched_freq_out[after_pass]++;
+ lsum = 0;
+ FOR_EACH_EDGE (e, ei, bb->succs)
+ lsum += e->count;
+ if (EDGE_COUNT (bb->succs)
+ && (lsum - bb->count > 100 || lsum - bb->count < -100))
+ record->num_mismatched_count_out[after_pass]++;
+ }
+ if (bb != ENTRY_BLOCK_PTR_FOR_FUNCTION (cfun)
+ && profile_status != PROFILE_ABSENT)
+ {
+ sum = 0;
+ FOR_EACH_EDGE (e, ei, bb->preds)
+ sum += EDGE_FREQUENCY (e);
+ if (abs (sum - bb->frequency) > 100
+ || (MAX (sum, bb->frequency) > 10
+ && abs ((sum - bb->frequency) * 100 / (MAX (sum, bb->frequency) + 1)) > 10))
+ record->num_mismatched_freq_in[after_pass]++;
+ lsum = 0;
+ FOR_EACH_EDGE (e, ei, bb->preds)
+ lsum += e->count;
+ if (lsum - bb->count > 100 || lsum - bb->count < -100)
+ record->num_mismatched_count_in[after_pass]++;
+ }
+ if (bb == ENTRY_BLOCK_PTR_FOR_FUNCTION (cfun)
+ || bb == EXIT_BLOCK_PTR_FOR_FUNCTION (cfun))
+ continue;
+ gcc_assert (cfg_hooks->account_profile_record);
+ cfg_hooks->account_profile_record(bb, after_pass, record);
+ }
+}