+static void
+remove_critical_edges (MonoCompile *cfg) {
+ MonoBasicBlock *bb;
+ MonoBasicBlock *previous_bb;
+
+ if (cfg->verbose_level > 3) {
+ for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
+ int i;
+ printf ("remove_critical_edges %s, BEFORE BB%d (in:", mono_method_full_name (cfg->method, TRUE), bb->block_num);
+ for (i = 0; i < bb->in_count; i++) {
+ printf (" %d", bb->in_bb [i]->block_num);
+ }
+ printf (") (out:");
+ for (i = 0; i < bb->out_count; i++) {
+ printf (" %d", bb->out_bb [i]->block_num);
+ }
+ printf (")");
+ if (bb->last_ins != NULL) {
+ printf (" ");
+ mono_print_tree (bb->last_ins);
+ }
+ printf ("\n");
+ }
+ }
+
+ for (previous_bb = cfg->bb_entry, bb = previous_bb->next_bb; bb != NULL; previous_bb = previous_bb->next_bb, bb = bb->next_bb) {
+ if (bb->in_count > 1) {
+ int in_bb_index;
+ for (in_bb_index = 0; in_bb_index < bb->in_count; in_bb_index++) {
+ MonoBasicBlock *in_bb = bb->in_bb [in_bb_index];
+ if (in_bb->out_count > 1) {
+ MonoBasicBlock *new_bb = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
+ new_bb->block_num = cfg->num_bblocks++;
+// new_bb->real_offset = bb->real_offset;
+ new_bb->region = bb->region;
+
+ /* Do not alter the CFG while altering the BB list */
+ if (previous_bb->region == bb->region) {
+ if (previous_bb != cfg->bb_entry) {
+ /* If previous_bb "followed through" to bb, */
+ /* keep it linked with a CEE_BR */
+ if ((previous_bb->last_ins == NULL) ||
+ ((previous_bb->last_ins->opcode != CEE_BR) &&
+ (! (MONO_IS_COND_BRANCH_OP (previous_bb->last_ins))) &&
+ (previous_bb->last_ins->opcode != CEE_SWITCH))) {
+ int i;
+ /* Make sure previous_bb really falls through bb */
+ for (i = 0; i < previous_bb->out_count; i++) {
+ if (previous_bb->out_bb [i] == bb) {
+ MonoInst *jump;
+ MONO_INST_NEW (cfg, jump, CEE_BR);
+ MONO_ADD_INS (previous_bb, jump);
+ jump->cil_code = previous_bb->cil_code;
+ jump->inst_target_bb = bb;
+ break;
+ }
+ }
+ }
+ } else {
+ /* We cannot add any inst to the entry BB, so we must */
+ /* put a new BB in the middle to hold the CEE_BR */
+ MonoInst *jump;
+ MonoBasicBlock *new_bb_after_entry = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
+ new_bb_after_entry->block_num = cfg->num_bblocks++;
+// new_bb_after_entry->real_offset = bb->real_offset;
+ new_bb_after_entry->region = bb->region;
+
+ MONO_INST_NEW (cfg, jump, CEE_BR);
+ MONO_ADD_INS (new_bb_after_entry, jump);
+ jump->cil_code = bb->cil_code;
+ jump->inst_target_bb = bb;
+
+ previous_bb->next_bb = new_bb_after_entry;
+ previous_bb = new_bb_after_entry;
+
+ if (cfg->verbose_level > 2) {
+ printf ("remove_critical_edges %s, added helper BB%d jumping to BB%d\n", mono_method_full_name (cfg->method, TRUE), new_bb_after_entry->block_num, bb->block_num);
+ }
+ }
+ }
+
+ /* Insert new_bb in the BB list */
+ previous_bb->next_bb = new_bb;
+ new_bb->next_bb = bb;
+ previous_bb = new_bb;
+
+ /* Setup in_bb and out_bb */
+ new_bb->in_bb = mono_mempool_alloc ((cfg)->mempool, sizeof (MonoBasicBlock*));
+ new_bb->in_bb [0] = in_bb;
+ new_bb->in_count = 1;
+ new_bb->out_bb = mono_mempool_alloc ((cfg)->mempool, sizeof (MonoBasicBlock*));
+ new_bb->out_bb [0] = bb;
+ new_bb->out_count = 1;
+
+ /* Relink in_bb and bb to (from) new_bb */
+ replace_out_block (in_bb, bb, new_bb);
+ replace_out_block_in_code (in_bb, bb, new_bb);
+ replace_in_block (bb, in_bb, new_bb);
+
+ if (cfg->verbose_level > 2) {
+ printf ("remove_critical_edges %s, removed critical edge from BB%d to BB%d (added BB%d)\n", mono_method_full_name (cfg->method, TRUE), in_bb->block_num, bb->block_num, new_bb->block_num);
+ }
+ }
+ }
+ }
+ }
+
+ if (cfg->verbose_level > 3) {
+ for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
+ int i;
+ printf ("remove_critical_edges %s, AFTER BB%d (in:", mono_method_full_name (cfg->method, TRUE), bb->block_num);
+ for (i = 0; i < bb->in_count; i++) {
+ printf (" %d", bb->in_bb [i]->block_num);
+ }
+ printf (") (out:");
+ for (i = 0; i < bb->out_count; i++) {
+ printf (" %d", bb->out_bb [i]->block_num);
+ }
+ printf (")");
+ if (bb->last_ins != NULL) {
+ printf (" ");
+ mono_print_tree (bb->last_ins);
+ }
+ printf ("\n");
+ }
+ }
+}
+