return jump;
}
+ return NULL;
+ } else {
+ /* Branching to an outer clause could skip inner clauses */
return NULL;
}
} else {
bb2 = bb->out_bb [1];
if (bb1->in_count == 1 && bb2->in_count == 1 && bb1->out_count == 1 && bb2->out_count == 1 && bb1->out_bb [0] == bb2->out_bb [0]) {
- MonoInst *prev, *compare, *branch, *ins1, *ins2, *cmov, *move, *tmp;
+ MonoInst *compare, *branch, *ins1, *ins2, *cmov, *move, *tmp;
MonoBasicBlock *true_bb, *false_bb;
gboolean simple, ret;
int dreg, tmp_reg;
continue;
/* Find the compare instruction */
- /* FIXME: Optimize this using prev */
- prev = NULL;
- compare = bb->code;
- g_assert (compare);
- while (compare->next && !MONO_IS_COND_BRANCH_OP (compare->next)) {
- prev = compare;
- compare = compare->next;
- }
- g_assert (compare->next && MONO_IS_COND_BRANCH_OP (compare->next));
- branch = compare->next;
+ if (!bb->last_ins || !bb->last_ins->prev)
+ continue;
+ branch = bb->last_ins;
+ compare = branch->prev;
+
+ if (!MONO_IS_COND_BRANCH_OP (branch))
+ /* This can happen if a cond branch is optimized away */
+ continue;
true_bb = branch->inst_true_bb;
false_bb = branch->inst_false_bb;
if ((bb2->in_count == 1 && bb2->out_count == 1 && bb2->out_bb [0] == bb1) ||
(bb1->in_count == 1 && bb1->out_count == 1 && bb1->out_bb [0] == bb2)) {
- MonoInst *prev, *compare, *branch, *ins1, *cmov, *tmp;
+ MonoInst *compare, *branch, *ins1, *cmov, *tmp;
gboolean simple;
int dreg, tmp_reg;
CompType comp_type;
continue;
/* Find the compare instruction */
- /* FIXME: Optimize this using prev */
- prev = NULL;
- compare = bb->code;
- g_assert (compare);
- while (compare->next && !MONO_IS_COND_BRANCH_OP (compare->next)) {
- prev = compare;
- compare = compare->next;
- }
- g_assert (compare->next && MONO_IS_COND_BRANCH_OP (compare->next));
- branch = compare->next;
+
+ if (!bb->last_ins || !bb->last_ins->prev)
+ continue;
+ branch = bb->last_ins;
+ compare = branch->prev;
+
+ if (!MONO_IS_COND_BRANCH_OP (branch))
+ /* This can happen if a cond branch is optimized away */
+ continue;
/* FIXME: */
comp_type = mono_opcode_to_type (branch->opcode, compare->opcode);
if ((bb->out_bb [0]->in_count == 1) && (bb->out_bb [0] != cfg->bb_exit) &&
(bb->region == bb->out_bb [0]->region)) {
mono_merge_basic_blocks (cfg, bb, bb->out_bb [0]);
+
+ /*
+ * bbn might have fallen through to the next bb without a branch,
+ * have to add one now (#474718).
+ * FIXME: Maybe need to do this more generally in
+ * merge_basic_blocks () ?
+ */
+ if (!(bb->last_ins && MONO_IS_BRANCH_OP (bb->last_ins)) && bb->out_count) {
+ MONO_INST_NEW (cfg, ins1, OP_BR);
+ ins1->inst_target_bb = bb->out_bb [0];
+ MONO_ADD_INS (bb, ins1);
+ }
goto restart;
}
}
mono_handle_global_vregs (cfg);
if (cfg->opt & (MONO_OPT_CONSPROP | MONO_OPT_COPYPROP))
mono_local_cprop (cfg);
- mono_local_deadce (cfg);
+ if (cfg->opt & MONO_OPT_DEADCE)
+ mono_local_deadce (cfg);
}
#endif
}
mono_unlink_bblock (cfg, bbn, bbn->out_bb [0]);
/* Handle the branch at the end of the bb */
- for (inst = bb->code; inst != NULL; inst = inst->next) {
- if (inst->opcode == OP_CALL_HANDLER) {
- g_assert (inst->inst_target_bb == bbn);
- NULLIFY_INS (inst);
+ if (bb->has_call_handler) {
+ for (inst = bb->code; inst != NULL; inst = inst->next) {
+ if (inst->opcode == OP_CALL_HANDLER) {
+ g_assert (inst->inst_target_bb == bbn);
+ NULLIFY_INS (inst);
+ }
}
- if (MONO_IS_JUMP_TABLE (inst)) {
- int i;
- MonoJumpInfoBBTable *table = MONO_JUMP_TABLE_FROM_INS (inst);
- for (i = 0; i < table->table_size; i++ ) {
- /* Might be already NULL from a previous merge */
- if (table->table [i])
- g_assert (table->table [i] == bbn);
- table->table [i] = NULL;
+ }
+ if (bb->has_jump_table) {
+ for (inst = bb->code; inst != NULL; inst = inst->next) {
+ if (MONO_IS_JUMP_TABLE (inst)) {
+ int i;
+ MonoJumpInfoBBTable *table = MONO_JUMP_TABLE_FROM_INS (inst);
+ for (i = 0; i < table->table_size; i++ ) {
+ /* Might be already NULL from a previous merge */
+ if (table->table [i])
+ g_assert (table->table [i] == bbn);
+ table->table [i] = NULL;
+ }
+ /* Can't nullify this as later instructions depend on it */
}
- /* Can't nullify this as later instructions depend on it */
}
}
if (bb->last_ins && MONO_IS_COND_BRANCH_OP (bb->last_ins)) {
NULLIFY_INS (bb->last_ins);
}
+ bb->has_call_handler |= bbn->has_call_handler;
+ bb->has_jump_table |= bbn->has_jump_table;
+
if (bb->last_ins) {
if (bbn->code) {
bb->last_ins->next = bbn->code;
bb->code = bbn->code;
bb->last_ins = bbn->last_ins;
}
+
for (prev_bb = cfg->bb_entry; prev_bb && prev_bb->next_bb != bbn; prev_bb = prev_bb->next_bb)
;
if (prev_bb) {
bb->next_bb = bbn->next_bb;
}
mono_nullify_basic_block (bbn);
+
+ /*
+ * If bbn fell through to its next bblock, have to add a branch, since bb
+ * will not fall though to the same bblock (#513931).
+ */
+ if (bb->last_ins && bb->out_count == 1 && bb->out_bb [0] != bb->next_bb && !MONO_IS_BRANCH_OP (bb->last_ins)) {
+ MONO_INST_NEW (cfg, inst, OP_BR);
+ inst->inst_target_bb = bb->out_bb [0];
+ MONO_ADD_INS (bb, inst);
+ }
}
static void
}
if (bb->last_ins && MONO_IS_COND_BRANCH_NOFP (bb->last_ins)) {
- if (bb->last_ins->inst_false_bb && bb->last_ins->inst_false_bb->out_of_line && (bb->region == bb->last_ins->inst_false_bb->region)) {
+ if (bb->last_ins->inst_false_bb && bb->last_ins->inst_false_bb->out_of_line && (bb->region == bb->last_ins->inst_false_bb->region) && !cfg->disable_out_of_line_bblocks) {
/* Reverse the branch */
bb->last_ins->opcode = mono_reverse_branch_op (bb->last_ins->opcode);
bbn = bb->last_ins->inst_false_bb;