2008-08-19 Zoltan Varga <vargaz@gmail.com>
[mono.git] / mono / mini / inssel-long32.brg
index b5909257bf9cb1e6f37662be892684d7b26f5fb6..a5efc25591a4e7e124f3738bebe168466ac8a24b 100644 (file)
@@ -101,7 +101,29 @@ reg: CEE_SUB_OVF_UN (reg, reg) {
        MONO_EMIT_NEW_COND_EXC (s, C, "OverflowException");
 }
 
-cflags: OP_COMPARE (reg, reg) {
+reg: CEE_DIV (reg, OP_ICONST) {
+       int p2 = mono_is_power_of_two (state->right->tree->inst_c0);
+       int r = mono_regstate_next_int (s->rs);
+       if (p2 <= 0) {
+               MONO_EMIT_NEW_ICONST (s, r, state->right->tree->inst_c0);
+               MONO_EMIT_BIALU (s, tree, CEE_DIV, state->reg1, state->left->reg1, r);
+       } else if (p2 == 1) {
+               int r2 = mono_regstate_next_int (s->rs);
+               MONO_EMIT_NEW_BIALU_IMM (s, OP_SHR_UN_IMM, r, state->left->reg1, 31);
+               MONO_EMIT_NEW_BIALU (s, CEE_ADD, r2, r, state->left->reg1);
+               MONO_EMIT_NEW_BIALU_IMM (s, OP_SHR_IMM, state->reg1, r2, 1);
+       } else {
+               int r2 = mono_regstate_next_int (s->rs);
+               int r3 = mono_regstate_next_int (s->rs);
+               int r4 = mono_regstate_next_int (s->rs);
+               MONO_EMIT_NEW_BIALU_IMM (s, OP_SHR_IMM, r2, state->left->reg1, 31);
+               MONO_EMIT_NEW_BIALU_IMM (s, OP_SHR_UN_IMM, r3, r2, (32 - p2));
+               MONO_EMIT_NEW_BIALU (s, CEE_ADD, r4, r3, state->left->reg1);
+               MONO_EMIT_NEW_BIALU_IMM (s, OP_SHR_IMM, state->reg1, r4, p2);
+       }
+}
+
+cflags: OP_COMPARE (reg, reg) "2" {
        tree->sreg1 = state->left->reg1;
        tree->sreg2 = state->right->reg1;
        mono_bblock_add_inst (s->cbb, tree);
@@ -110,7 +132,7 @@ cflags: OP_COMPARE (reg, reg) {
 cflags: OP_COMPARE (CEE_LDIND_REF (OP_REGVAR), reg),
 cflags: OP_COMPARE (CEE_LDIND_I (OP_REGVAR), reg),
 cflags: OP_COMPARE (CEE_LDIND_I4 (OP_REGVAR), reg),
-cflags: OP_COMPARE (CEE_LDIND_U4 (OP_REGVAR), reg) {
+cflags: OP_COMPARE (CEE_LDIND_U4 (OP_REGVAR), reg) "2" {
        tree->sreg1 = state->left->left->tree->dreg;
        tree->sreg2 = state->right->reg1;
        mono_bblock_add_inst (s->cbb, tree);
@@ -119,7 +141,7 @@ cflags: OP_COMPARE (CEE_LDIND_U4 (OP_REGVAR), reg) {
 cflags: OP_COMPARE (CEE_LDIND_REF (OP_REGVAR), CEE_LDIND_REF (OP_REGVAR)),
 cflags: OP_COMPARE (CEE_LDIND_I (OP_REGVAR), CEE_LDIND_I (OP_REGVAR)),
 cflags: OP_COMPARE (CEE_LDIND_I4 (OP_REGVAR), CEE_LDIND_I4 (OP_REGVAR)),
-cflags: OP_COMPARE (CEE_LDIND_U4 (OP_REGVAR), CEE_LDIND_U4 (OP_REGVAR)) {
+cflags: OP_COMPARE (CEE_LDIND_U4 (OP_REGVAR), CEE_LDIND_U4 (OP_REGVAR)) "2" {
        tree->sreg1 = state->left->left->tree->dreg;
        tree->sreg2 = state->right->left->tree->dreg;
        mono_bblock_add_inst (s->cbb, tree);
@@ -128,14 +150,14 @@ cflags: OP_COMPARE (CEE_LDIND_U4 (OP_REGVAR), CEE_LDIND_U4 (OP_REGVAR)) {
 cflags: OP_COMPARE (CEE_LDIND_REF (OP_REGVAR), OP_ICONST),
 cflags: OP_COMPARE (CEE_LDIND_I (OP_REGVAR), OP_ICONST),
 cflags: OP_COMPARE (CEE_LDIND_I4 (OP_REGVAR), OP_ICONST),
-cflags: OP_COMPARE (CEE_LDIND_U4 (OP_REGVAR), OP_ICONST) {
+cflags: OP_COMPARE (CEE_LDIND_U4 (OP_REGVAR), OP_ICONST) "2" {
        tree->opcode = OP_COMPARE_IMM;
        tree->sreg1 = state->left->left->tree->dreg;
        tree->inst_imm = state->right->tree->inst_c0;
        mono_bblock_add_inst (s->cbb, tree);
 }
 
-cflags: OP_COMPARE (reg, OP_ICONST) {
+cflags: OP_COMPARE (reg, OP_ICONST) "2" {
        tree->opcode = OP_COMPARE_IMM;
        tree->sreg1 = state->left->reg1;
        tree->inst_imm = state->right->tree->inst_c0;
@@ -151,7 +173,7 @@ stmt: CEE_BGT_UN (cflags),
 stmt: CEE_BGE  (cflags),
 stmt: CEE_BGE_UN (cflags),
 stmt: CEE_BLE  (cflags),
-stmt: CEE_BLE_UN (cflags) {
+stmt: CEE_BLE_UN (cflags) "2" {
        mono_bblock_add_inst (s->cbb, tree);
 }
 
@@ -159,7 +181,7 @@ reg: OP_CEQ (cflags),
 reg: OP_CLT (cflags),
 reg: OP_CLT_UN (cflags),
 reg: OP_CGT (cflags),
-reg: OP_CGT_UN (cflags) {      
+reg: OP_CGT_UN (cflags) "2" {  
        tree->dreg = state->reg1;
        mono_bblock_add_inst (s->cbb, tree);
 }
@@ -238,27 +260,27 @@ lreg: OP_BIGMUL_UN (reg, reg) {
        MONO_EMIT_NEW_BIALU (s, tree->opcode, state->reg1, state->left->reg1, state->right->reg1); 
 }
 
-lreg: OP_LONG_SHRUN_32 (lreg) {
+lreg: OP_LSHR_UN_32 (lreg) {
        /* just move the upper half to the lower and zero the high word */
        MONO_EMIT_NEW_UNALU (s, OP_MOVE, state->reg1, state->left->reg2);
        MONO_EMIT_NEW_ICONST (s, state->reg2, 0);
 }
 
-reg: OP_LCONV_TO_I4 (OP_LONG_SHRUN_32 (lreg)),
-reg: OP_LCONV_TO_U4 (OP_LONG_SHRUN_32 (lreg)) {
+reg: OP_LCONV_TO_I4 (OP_LSHR_UN_32 (lreg)),
+reg: OP_LCONV_TO_U4 (OP_LSHR_UN_32 (lreg)) {
        MONO_EMIT_NEW_UNALU (s, OP_MOVE, state->reg1, state->left->left->reg2);
 }
 
 
-lreg: OP_LONG_SHRUN_32 (CEE_LDIND_I8 (base)) {
+lreg: OP_LSHR_UN_32 (CEE_LDIND_I8 (base)) {
        /* just move the upper half to the lower and zero the high word */
        MONO_EMIT_NEW_LOAD_MEMBASE_OP (s, OP_LOADI4_MEMBASE, state->reg1, 
                                       state->left->left->tree->inst_basereg, state->left->left->tree->inst_offset + MINI_MS_WORD_OFFSET);
        MONO_EMIT_NEW_ICONST (s, state->reg2, 0);
 }
 
-reg: OP_LCONV_TO_I4 (OP_LONG_SHRUN_32 (CEE_LDIND_I8 (base))),
-reg: OP_LCONV_TO_U4 (OP_LONG_SHRUN_32 (CEE_LDIND_I8 (base))) {
+reg: OP_LCONV_TO_I4 (OP_LSHR_UN_32 (CEE_LDIND_I8 (base))),
+reg: OP_LCONV_TO_U4 (OP_LSHR_UN_32 (CEE_LDIND_I8 (base))) {
        /* just move the upper half to the lower and zero the high word */
        MONO_EMIT_NEW_LOAD_MEMBASE_OP (s, OP_LOADI4_MEMBASE, state->reg1, 
                                       state->left->left->left->tree->inst_basereg,
@@ -362,10 +384,8 @@ reg: OP_CEQ (OP_LCOMPARE (lreg, lreg)) {
        MONO_NEW_LABEL (s, word_differs);
 
        MONO_EMIT_NEW_ICONST (s, state->reg1, 0);
-       MONO_EMIT_NEW_BIALU (s, OP_COMPARE, -1, state->left->left->reg2, state->left->right->reg2);
-       MONO_EMIT_NEW_BRANCH_LABEL (s, CEE_BNE_UN, word_differs);
-       MONO_EMIT_NEW_BIALU (s, OP_COMPARE, -1, state->left->left->reg1, state->left->right->reg1);
-       MONO_EMIT_NEW_BRANCH_LABEL (s, CEE_BNE_UN, word_differs);
+       MONO_EMIT_NEW_COMPARE_BRANCH_LABEL (s, CEE_BNE_UN, state->left->left->reg2, state->left->right->reg2, word_differs);
+       MONO_EMIT_NEW_COMPARE_BRANCH_LABEL (s, CEE_BNE_UN, state->left->left->reg1, state->left->right->reg1, word_differs);
        MONO_EMIT_NEW_ICONST (s, state->reg1, 1);
        
        mono_bblock_add_inst (s->cbb, word_differs);
@@ -378,11 +398,9 @@ reg: OP_CLT (OP_LCOMPARE (lreg, lreg)) {
        MONO_NEW_LABEL (s, set_to_1);
 
        MONO_EMIT_NEW_ICONST (s, state->reg1, 0);
-       MONO_EMIT_NEW_BIALU (s, OP_COMPARE, -1, state->left->left->reg2, state->left->right->reg2);
-       MONO_EMIT_NEW_BRANCH_LABEL (s, CEE_BGT, set_to_0);
-       MONO_EMIT_NEW_BRANCH_LABEL (s, CEE_BNE_UN, set_to_1);
-       MONO_EMIT_NEW_BIALU (s, OP_COMPARE, -1, state->left->left->reg1, state->left->right->reg1);
-       MONO_EMIT_NEW_BRANCH_LABEL (s, CEE_BGE_UN, set_to_0);
+       MONO_EMIT_NEW_COMPARE_BRANCH_LABEL (s, CEE_BGT, state->left->left->reg2, state->left->right->reg2, set_to_0);
+       MONO_EMIT_NEW_COMPARE_BRANCH_LABEL_CHAINED (s, CEE_BNE_UN, state->left->left->reg2, state->left->right->reg2, set_to_1);
+       MONO_EMIT_NEW_COMPARE_BRANCH_LABEL (s, CEE_BGE_UN, state->left->left->reg1, state->left->right->reg1, set_to_0);
        mono_bblock_add_inst (s->cbb, set_to_1);
        MONO_EMIT_NEW_ICONST (s, state->reg1, 1);
        mono_bblock_add_inst (s->cbb, set_to_0);
@@ -395,11 +413,9 @@ reg: OP_CLT_UN (OP_LCOMPARE (lreg, lreg)) {
        MONO_NEW_LABEL (s, set_to_1);
 
        MONO_EMIT_NEW_ICONST (s, state->reg1, 0);
-       MONO_EMIT_NEW_BIALU (s, OP_COMPARE, -1, state->left->left->reg2, state->left->right->reg2);
-       MONO_EMIT_NEW_BRANCH_LABEL (s, CEE_BGT_UN, set_to_0);
-       MONO_EMIT_NEW_BRANCH_LABEL (s, CEE_BNE_UN, set_to_1);
-       MONO_EMIT_NEW_BIALU (s, OP_COMPARE, -1, state->left->left->reg1, state->left->right->reg1);
-       MONO_EMIT_NEW_BRANCH_LABEL (s, CEE_BGE_UN, set_to_0);
+       MONO_EMIT_NEW_COMPARE_BRANCH_LABEL (s, CEE_BGT_UN, state->left->left->reg2, state->left->right->reg2, set_to_0);
+       MONO_EMIT_NEW_COMPARE_BRANCH_LABEL_CHAINED (s, CEE_BNE_UN, state->left->left->reg2, state->left->right->reg2, set_to_1);
+       MONO_EMIT_NEW_COMPARE_BRANCH_LABEL (s, CEE_BGE_UN, state->left->left->reg1, state->left->right->reg1, set_to_0);
        mono_bblock_add_inst (s->cbb, set_to_1);
        MONO_EMIT_NEW_ICONST (s, state->reg1, 1);
        mono_bblock_add_inst (s->cbb, set_to_0);
@@ -412,11 +428,9 @@ reg: OP_CGT (OP_LCOMPARE (lreg, lreg)) {
        MONO_NEW_LABEL (s, set_to_1);
 
        MONO_EMIT_NEW_ICONST (s, state->reg1, 0);
-       MONO_EMIT_NEW_BIALU (s, OP_COMPARE, -1, state->left->right->reg2, state->left->left->reg2);
-       MONO_EMIT_NEW_BRANCH_LABEL (s, CEE_BGT, set_to_0);
-       MONO_EMIT_NEW_BRANCH_LABEL (s, CEE_BNE_UN, set_to_1);
-       MONO_EMIT_NEW_BIALU (s, OP_COMPARE, -1, state->left->right->reg1, state->left->left->reg1);
-       MONO_EMIT_NEW_BRANCH_LABEL (s, CEE_BGE_UN, set_to_0);
+       MONO_EMIT_NEW_COMPARE_BRANCH_LABEL (s, CEE_BGT, state->left->right->reg2, state->left->left->reg2, set_to_0);
+       MONO_EMIT_NEW_COMPARE_BRANCH_LABEL_CHAINED (s, CEE_BNE_UN, state->left->right->reg2, state->left->left->reg2, set_to_1);
+       MONO_EMIT_NEW_COMPARE_BRANCH_LABEL (s, CEE_BGE_UN, state->left->right->reg1, state->left->left->reg1, set_to_0);
        mono_bblock_add_inst (s->cbb, set_to_1);
        MONO_EMIT_NEW_ICONST (s, state->reg1, 1);
        mono_bblock_add_inst (s->cbb, set_to_0);
@@ -429,188 +443,129 @@ reg: OP_CGT_UN (OP_LCOMPARE (lreg, lreg)) {
        MONO_NEW_LABEL (s, set_to_1);
 
        MONO_EMIT_NEW_ICONST (s, state->reg1, 0);
-       MONO_EMIT_NEW_BIALU (s, OP_COMPARE, -1, state->left->right->reg2, state->left->left->reg2);
-       MONO_EMIT_NEW_BRANCH_LABEL (s, CEE_BGT_UN, set_to_0);
-       MONO_EMIT_NEW_BRANCH_LABEL (s, CEE_BNE_UN, set_to_1);
-       MONO_EMIT_NEW_BIALU (s, OP_COMPARE, -1, state->left->right->reg1, state->left->left->reg1);
-       MONO_EMIT_NEW_BRANCH_LABEL (s, CEE_BGE_UN, set_to_0);
+       MONO_EMIT_NEW_COMPARE_BRANCH_LABEL (s, CEE_BGT_UN, state->left->right->reg2, state->left->left->reg2, set_to_0);
+       MONO_EMIT_NEW_COMPARE_BRANCH_LABEL_CHAINED (s, CEE_BNE_UN, state->left->right->reg2, state->left->left->reg2, set_to_1);
+       MONO_EMIT_NEW_COMPARE_BRANCH_LABEL (s, CEE_BGE_UN, state->left->right->reg1, state->left->left->reg1, set_to_0);
        mono_bblock_add_inst (s->cbb, set_to_1);
        MONO_EMIT_NEW_ICONST (s, state->reg1, 1);
        mono_bblock_add_inst (s->cbb, set_to_0);
 }      
 
 stmt: CEE_BNE_UN (OP_LCOMPARE (lreg, lreg)) {
-       MONO_EMIT_NEW_BIALU (s, OP_COMPARE, -1, state->left->left->reg1, state->left->right->reg1);
-       MONO_EMIT_NEW_BRANCH_BLOCK (s, CEE_BNE_UN, tree->inst_true_bb);
-       MONO_EMIT_NEW_BIALU (s, OP_COMPARE, -1, state->left->left->reg2, state->left->right->reg2);
-       mono_bblock_add_inst (s->cbb, tree);
+       MONO_EMIT_NEW_COMPARE_BRANCH_BLOCK (s, CEE_BNE_UN, state->left->left->reg1, state->left->right->reg1, tree->inst_true_bb);
+       MONO_EMIT_NEW_COMPARE_BRANCH_BLOCK (s, CEE_BNE_UN, state->left->left->reg2, state->left->right->reg2, tree->inst_true_bb);
 }
 
 stmt: CEE_BNE_UN (OP_LCOMPARE (lreg, i8con)) {
-       MONO_EMIT_NEW_BIALU_IMM (s, OP_COMPARE_IMM, -1, state->left->left->reg1, state->left->right->tree->inst_ls_word);
-       MONO_EMIT_NEW_BRANCH_BLOCK (s, CEE_BNE_UN, tree->inst_true_bb);
-       MONO_EMIT_NEW_BIALU_IMM (s, OP_COMPARE_IMM, -1, state->left->left->reg2, state->left->right->tree->inst_ms_word);
-       mono_bblock_add_inst (s->cbb, tree);
+       MONO_EMIT_NEW_COMPARE_IMM_BRANCH_BLOCK (s, CEE_BNE_UN, state->left->left->reg1, state->left->right->tree->inst_ls_word, tree->inst_true_bb);
+       MONO_EMIT_NEW_COMPARE_IMM_BRANCH_BLOCK (s, CEE_BNE_UN, state->left->left->reg2, state->left->right->tree->inst_ms_word, tree->inst_true_bb);
 }
 
 stmt: CEE_BEQ (OP_LCOMPARE (lreg, lreg)) {
-       
-       MONO_EMIT_NEW_BIALU (s, OP_COMPARE, -1, state->left->left->reg1, state->left->right->reg1);
-       MONO_EMIT_NEW_BRANCH_BLOCK (s, CEE_BNE_UN, tree->inst_false_bb);
-       MONO_EMIT_NEW_BIALU (s, OP_COMPARE, -1, state->left->left->reg2, state->left->right->reg2);
-       mono_bblock_add_inst (s->cbb, tree);
+       MONO_EMIT_NEW_COMPARE_BRANCH_BLOCK (s, CEE_BNE_UN, state->left->left->reg1, state->left->right->reg1, tree->inst_false_bb);
+       MONO_EMIT_NEW_COMPARE_BRANCH_BLOCK (s, CEE_BEQ, state->left->left->reg2, state->left->right->reg2, tree->inst_true_bb);
 }
 
 stmt: CEE_BEQ (OP_LCOMPARE (lreg, i8con)) {
-       
-       MONO_EMIT_NEW_BIALU_IMM (s, OP_COMPARE_IMM, -1, state->left->left->reg1, state->left->right->tree->inst_ls_word);
-       MONO_EMIT_NEW_BRANCH_BLOCK (s, CEE_BNE_UN, tree->inst_false_bb);
-       MONO_EMIT_NEW_BIALU_IMM (s, OP_COMPARE_IMM, -1, state->left->left->reg2, state->left->right->tree->inst_ms_word);
-       mono_bblock_add_inst (s->cbb, tree);
+       MONO_EMIT_NEW_COMPARE_IMM_BRANCH_BLOCK (s, CEE_BNE_UN, state->left->left->reg1, state->left->right->tree->inst_ls_word, tree->inst_false_bb);
+       MONO_EMIT_NEW_COMPARE_IMM_BRANCH_BLOCK (s, CEE_BEQ, state->left->left->reg2, state->left->right->tree->inst_ms_word, tree->inst_true_bb);
 }
 
 stmt: CEE_BLE (OP_LCOMPARE (lreg, lreg)) {
-
-       MONO_EMIT_NEW_BIALU (s, OP_COMPARE, -1, state->left->left->reg2, state->left->right->reg2);
-       MONO_EMIT_NEW_BRANCH_BLOCK (s, CEE_BLT, tree->inst_true_bb);
-       MONO_EMIT_NEW_BRANCH_BLOCK (s, CEE_BNE_UN, tree->inst_false_bb);
-       MONO_EMIT_NEW_BIALU (s, OP_COMPARE, -1, state->left->left->reg1, state->left->right->reg1);
-       MONO_EMIT_NEW_BRANCH_BLOCK (s, CEE_BLE_UN, tree->inst_true_bb);
+       MONO_EMIT_NEW_COMPARE_BRANCH_BLOCK (s, CEE_BLT, state->left->left->reg2, state->left->right->reg2, tree->inst_true_bb);
+       MONO_EMIT_NEW_COMPARE_BRANCH_BLOCK_CHAINED (s, CEE_BNE_UN, state->left->left->reg2, state->left->right->reg2, tree->inst_false_bb);
+       MONO_EMIT_NEW_COMPARE_BRANCH_BLOCK (s, CEE_BLE_UN, state->left->left->reg1, state->left->right->reg1, tree->inst_true_bb);
 }
 
 stmt: CEE_BLE (OP_LCOMPARE (lreg, i8con)) {
-
-       MONO_EMIT_NEW_BIALU_IMM (s, OP_COMPARE_IMM, -1, state->left->left->reg2, state->left->right->tree->inst_ms_word);
-       MONO_EMIT_NEW_BRANCH_BLOCK (s, CEE_BLT, tree->inst_true_bb);
-       MONO_EMIT_NEW_BRANCH_BLOCK (s, CEE_BNE_UN, tree->inst_false_bb);
-       MONO_EMIT_NEW_BIALU_IMM (s, OP_COMPARE_IMM, -1, state->left->left->reg1, state->left->right->tree->inst_ls_word);
-       MONO_EMIT_NEW_BRANCH_BLOCK (s, CEE_BLE_UN, tree->inst_true_bb);
+       MONO_EMIT_NEW_COMPARE_IMM_BRANCH_BLOCK (s, CEE_BLT, state->left->left->reg2, state->left->right->tree->inst_ms_word, tree->inst_true_bb);
+       MONO_EMIT_NEW_COMPARE_IMM_BRANCH_BLOCK_CHAINED (s, CEE_BNE_UN, state->left->left->reg2, state->left->right->tree->inst_ms_word, tree->inst_false_bb);
+       MONO_EMIT_NEW_COMPARE_IMM_BRANCH_BLOCK (s, CEE_BLE_UN, state->left->left->reg1, state->left->right->tree->inst_ls_word, tree->inst_true_bb);
 }
 
 stmt: CEE_BLE_UN (OP_LCOMPARE (lreg, lreg)) {
-
-       MONO_EMIT_NEW_BIALU (s, OP_COMPARE, -1, state->left->left->reg2, state->left->right->reg2);
-       MONO_EMIT_NEW_BRANCH_BLOCK (s, CEE_BLT_UN, tree->inst_true_bb);
-       MONO_EMIT_NEW_BRANCH_BLOCK (s, CEE_BNE_UN, tree->inst_false_bb);
-       MONO_EMIT_NEW_BIALU (s, OP_COMPARE, -1, state->left->left->reg1, state->left->right->reg1);
-       MONO_EMIT_NEW_BRANCH_BLOCK (s, CEE_BLE_UN, tree->inst_true_bb);
+       MONO_EMIT_NEW_COMPARE_BRANCH_BLOCK (s, CEE_BLT_UN, state->left->left->reg2, state->left->right->reg2, tree->inst_true_bb);
+       MONO_EMIT_NEW_COMPARE_BRANCH_BLOCK_CHAINED (s, CEE_BNE_UN, state->left->left->reg2, state->left->right->reg2, tree->inst_false_bb);
+       MONO_EMIT_NEW_COMPARE_BRANCH_BLOCK (s, CEE_BLE_UN, state->left->left->reg1, state->left->right->reg1, tree->inst_true_bb);
 }
 
 stmt: CEE_BLE_UN (OP_LCOMPARE (lreg, i8con)) {
 
-       MONO_EMIT_NEW_BIALU_IMM (s, OP_COMPARE_IMM, -1, state->left->left->reg2, state->left->right->tree->inst_ms_word);
-       MONO_EMIT_NEW_BRANCH_BLOCK (s, CEE_BLT_UN, tree->inst_true_bb);
-       MONO_EMIT_NEW_BRANCH_BLOCK (s, CEE_BNE_UN, tree->inst_false_bb);
-       MONO_EMIT_NEW_BIALU_IMM (s, OP_COMPARE_IMM, -1, state->left->left->reg1, state->left->right->tree->inst_ls_word);
-       MONO_EMIT_NEW_BRANCH_BLOCK (s, CEE_BLE_UN, tree->inst_true_bb);
+       MONO_EMIT_NEW_COMPARE_IMM_BRANCH_BLOCK (s, CEE_BLT_UN, state->left->left->reg2, state->left->right->tree->inst_ms_word, tree->inst_true_bb);
+       MONO_EMIT_NEW_COMPARE_IMM_BRANCH_BLOCK_CHAINED (s, CEE_BNE_UN, state->left->left->reg2, state->left->right->tree->inst_ms_word, tree->inst_false_bb);
+       MONO_EMIT_NEW_COMPARE_IMM_BRANCH_BLOCK (s, CEE_BLE_UN, state->left->left->reg1, state->left->right->tree->inst_ls_word, tree->inst_true_bb);
 }
 
 stmt: CEE_BGE (OP_LCOMPARE (lreg, lreg)) {
-
-       MONO_EMIT_NEW_BIALU (s, OP_COMPARE, -1, state->left->left->reg2, state->left->right->reg2);
-       MONO_EMIT_NEW_BRANCH_BLOCK (s, CEE_BGT, tree->inst_true_bb);
-       MONO_EMIT_NEW_BRANCH_BLOCK (s, CEE_BNE_UN, tree->inst_false_bb);
-       MONO_EMIT_NEW_BIALU (s, OP_COMPARE, -1, state->left->left->reg1, state->left->right->reg1);
-       MONO_EMIT_NEW_BRANCH_BLOCK (s, CEE_BGE_UN, tree->inst_true_bb);
+       MONO_EMIT_NEW_COMPARE_BRANCH_BLOCK (s, CEE_BGT, state->left->left->reg2, state->left->right->reg2, tree->inst_true_bb);
+       MONO_EMIT_NEW_COMPARE_BRANCH_BLOCK_CHAINED (s, CEE_BNE_UN, state->left->left->reg2, state->left->right->reg2, tree->inst_false_bb);
+       MONO_EMIT_NEW_COMPARE_BRANCH_BLOCK (s, CEE_BGE_UN, state->left->left->reg1, state->left->right->reg1, tree->inst_true_bb);
 }
 
 stmt: CEE_BGE (OP_LCOMPARE (lreg, i8con)) {
-
-       MONO_EMIT_NEW_BIALU_IMM (s, OP_COMPARE_IMM, -1, state->left->left->reg2, state->left->right->tree->inst_ms_word);
-       MONO_EMIT_NEW_BRANCH_BLOCK (s, CEE_BGT, tree->inst_true_bb);
-       MONO_EMIT_NEW_BRANCH_BLOCK (s, CEE_BNE_UN, tree->inst_false_bb);
-       MONO_EMIT_NEW_BIALU_IMM (s, OP_COMPARE_IMM, -1, state->left->left->reg1, state->left->right->tree->inst_ls_word);
-       MONO_EMIT_NEW_BRANCH_BLOCK (s, CEE_BGE_UN, tree->inst_true_bb);
+       MONO_EMIT_NEW_COMPARE_IMM_BRANCH_BLOCK (s, CEE_BGT, state->left->left->reg2, state->left->right->tree->inst_ms_word, tree->inst_true_bb);
+       MONO_EMIT_NEW_COMPARE_IMM_BRANCH_BLOCK_CHAINED (s, CEE_BNE_UN, state->left->left->reg2, state->left->right->tree->inst_ms_word, tree->inst_false_bb);
+       MONO_EMIT_NEW_COMPARE_IMM_BRANCH_BLOCK (s, CEE_BGE_UN, state->left->left->reg1, state->left->right->tree->inst_ls_word, tree->inst_true_bb);
 }
 
 stmt: CEE_BGE_UN (OP_LCOMPARE (lreg, lreg)) {
-
-       MONO_EMIT_NEW_BIALU (s, OP_COMPARE, -1, state->left->left->reg2, state->left->right->reg2);
-       MONO_EMIT_NEW_BRANCH_BLOCK (s, CEE_BGT_UN, tree->inst_true_bb);
-       MONO_EMIT_NEW_BRANCH_BLOCK (s, CEE_BNE_UN, tree->inst_false_bb);
-       MONO_EMIT_NEW_BIALU (s, OP_COMPARE, -1, state->left->left->reg1, state->left->right->reg1);
-       MONO_EMIT_NEW_BRANCH_BLOCK (s, CEE_BGE_UN, tree->inst_true_bb);
+       MONO_EMIT_NEW_COMPARE_BRANCH_BLOCK (s, CEE_BGT_UN, state->left->left->reg2, state->left->right->reg2, tree->inst_true_bb);
+       MONO_EMIT_NEW_COMPARE_BRANCH_BLOCK_CHAINED (s, CEE_BNE_UN, state->left->left->reg2, state->left->right->reg2, tree->inst_false_bb);
+       MONO_EMIT_NEW_COMPARE_BRANCH_BLOCK (s, CEE_BGE_UN, state->left->left->reg1, state->left->right->reg1, tree->inst_true_bb);
 }
 
 stmt: CEE_BGE_UN (OP_LCOMPARE (lreg, i8con)) {
-
-       MONO_EMIT_NEW_BIALU_IMM (s, OP_COMPARE_IMM, -1, state->left->left->reg2, state->left->right->tree->inst_ms_word);
-       MONO_EMIT_NEW_BRANCH_BLOCK (s, CEE_BGT_UN, tree->inst_true_bb);
-       MONO_EMIT_NEW_BRANCH_BLOCK (s, CEE_BNE_UN, tree->inst_false_bb);
-       MONO_EMIT_NEW_BIALU_IMM (s, OP_COMPARE_IMM, -1, state->left->left->reg1, state->left->right->tree->inst_ls_word);
-       MONO_EMIT_NEW_BRANCH_BLOCK (s, CEE_BGE_UN, tree->inst_true_bb);
+       MONO_EMIT_NEW_COMPARE_IMM_BRANCH_BLOCK (s, CEE_BGT_UN, state->left->left->reg2, state->left->right->tree->inst_ms_word, tree->inst_true_bb);
+       MONO_EMIT_NEW_COMPARE_IMM_BRANCH_BLOCK_CHAINED (s, CEE_BNE_UN, state->left->left->reg2, state->left->right->tree->inst_ms_word, tree->inst_false_bb);
+       MONO_EMIT_NEW_COMPARE_IMM_BRANCH_BLOCK (s, CEE_BGE_UN, state->left->left->reg1, state->left->right->tree->inst_ls_word, tree->inst_true_bb);
 }
 
 stmt: CEE_BLT (OP_LCOMPARE (lreg, lreg)) {
-
-       MONO_EMIT_NEW_BIALU (s, OP_COMPARE, -1, state->left->left->reg2, state->left->right->reg2);
-       MONO_EMIT_NEW_BRANCH_BLOCK (s, CEE_BLT, tree->inst_true_bb);
-       MONO_EMIT_NEW_BRANCH_BLOCK (s, CEE_BNE_UN, tree->inst_false_bb);
-       MONO_EMIT_NEW_BIALU (s, OP_COMPARE, -1, state->left->left->reg1, state->left->right->reg1);
-       MONO_EMIT_NEW_BRANCH_BLOCK (s, CEE_BLT_UN, tree->inst_true_bb);
+       MONO_EMIT_NEW_COMPARE_BRANCH_BLOCK (s, CEE_BLT, state->left->left->reg2, state->left->right->reg2, tree->inst_true_bb);
+       MONO_EMIT_NEW_COMPARE_BRANCH_BLOCK_CHAINED (s, CEE_BNE_UN, state->left->left->reg2, state->left->right->reg2, tree->inst_false_bb);
+       MONO_EMIT_NEW_COMPARE_BRANCH_BLOCK (s, CEE_BLT_UN, state->left->left->reg1, state->left->right->reg1, tree->inst_true_bb);
 }
 
 stmt: CEE_BLT (OP_LCOMPARE (lreg, i8con)) {
-
-       MONO_EMIT_NEW_BIALU_IMM (s, OP_COMPARE_IMM, -1, state->left->left->reg2, state->left->right->tree->inst_ms_word);
-       MONO_EMIT_NEW_BRANCH_BLOCK (s, CEE_BLT, tree->inst_true_bb);
-       MONO_EMIT_NEW_BRANCH_BLOCK (s, CEE_BNE_UN, tree->inst_false_bb);
-       MONO_EMIT_NEW_BIALU_IMM (s, OP_COMPARE_IMM, -1, state->left->left->reg1, state->left->right->tree->inst_ls_word);
-       MONO_EMIT_NEW_BRANCH_BLOCK (s, CEE_BLT_UN, tree->inst_true_bb);
+       MONO_EMIT_NEW_COMPARE_IMM_BRANCH_BLOCK (s, CEE_BLT, state->left->left->reg2, state->left->right->tree->inst_ms_word, tree->inst_true_bb);
+       MONO_EMIT_NEW_COMPARE_IMM_BRANCH_BLOCK_CHAINED (s, CEE_BNE_UN, state->left->left->reg2, state->left->right->tree->inst_ms_word, tree->inst_false_bb);
+       MONO_EMIT_NEW_COMPARE_IMM_BRANCH_BLOCK (s, CEE_BLT_UN, state->left->left->reg1, state->left->right->tree->inst_ls_word, tree->inst_true_bb);
 }
 
 stmt: CEE_BLT_UN (OP_LCOMPARE (lreg, lreg)) {
-
-       MONO_EMIT_NEW_BIALU (s, OP_COMPARE, -1, state->left->left->reg2, state->left->right->reg2);
-       MONO_EMIT_NEW_BRANCH_BLOCK (s, CEE_BLT_UN, tree->inst_true_bb);
-       MONO_EMIT_NEW_BRANCH_BLOCK (s, CEE_BNE_UN, tree->inst_false_bb);
-       MONO_EMIT_NEW_BIALU (s, OP_COMPARE, -1, state->left->left->reg1, state->left->right->reg1);
-       MONO_EMIT_NEW_BRANCH_BLOCK (s, CEE_BLT_UN, tree->inst_true_bb);
+       MONO_EMIT_NEW_COMPARE_BRANCH_BLOCK (s, CEE_BLT_UN, state->left->left->reg2, state->left->right->reg2, tree->inst_true_bb);
+       MONO_EMIT_NEW_COMPARE_BRANCH_BLOCK_CHAINED (s, CEE_BNE_UN, state->left->left->reg2, state->left->right->reg2, tree->inst_false_bb);
+       MONO_EMIT_NEW_COMPARE_BRANCH_BLOCK (s, CEE_BLT_UN, state->left->left->reg1, state->left->right->reg1, tree->inst_true_bb);
 }
 
 stmt: CEE_BLT_UN (OP_LCOMPARE (lreg, i8con)) {
-
-       MONO_EMIT_NEW_BIALU_IMM (s, OP_COMPARE_IMM, -1, state->left->left->reg2, state->left->right->tree->inst_ms_word);
-       MONO_EMIT_NEW_BRANCH_BLOCK (s, CEE_BLT_UN, tree->inst_true_bb);
-       MONO_EMIT_NEW_BRANCH_BLOCK (s, CEE_BNE_UN, tree->inst_false_bb);
-       MONO_EMIT_NEW_BIALU_IMM (s, OP_COMPARE_IMM, -1, state->left->left->reg1, state->left->right->tree->inst_ls_word);
-       MONO_EMIT_NEW_BRANCH_BLOCK (s, CEE_BLT_UN, tree->inst_true_bb);
+       MONO_EMIT_NEW_COMPARE_IMM_BRANCH_BLOCK (s, CEE_BLT_UN, state->left->left->reg2, state->left->right->tree->inst_ms_word, tree->inst_true_bb);
+       MONO_EMIT_NEW_COMPARE_IMM_BRANCH_BLOCK_CHAINED (s, CEE_BNE_UN, state->left->left->reg2, state->left->right->tree->inst_ms_word, tree->inst_false_bb);
+       MONO_EMIT_NEW_COMPARE_IMM_BRANCH_BLOCK (s, CEE_BLT_UN, state->left->left->reg1, state->left->right->tree->inst_ls_word, tree->inst_true_bb);
 }
 
 stmt: CEE_BGT (OP_LCOMPARE (lreg, lreg)) {
-
-       MONO_EMIT_NEW_BIALU (s, OP_COMPARE, -1, state->left->left->reg2, state->left->right->reg2);
-       MONO_EMIT_NEW_BRANCH_BLOCK (s, CEE_BGT, tree->inst_true_bb);
-       MONO_EMIT_NEW_BRANCH_BLOCK (s, CEE_BNE_UN, tree->inst_false_bb);
-       MONO_EMIT_NEW_BIALU (s, OP_COMPARE, -1, state->left->left->reg1, state->left->right->reg1);
-       MONO_EMIT_NEW_BRANCH_BLOCK (s, CEE_BGT_UN, tree->inst_true_bb);
+       MONO_EMIT_NEW_COMPARE_BRANCH_BLOCK (s, CEE_BGT, state->left->left->reg2, state->left->right->reg2, tree->inst_true_bb);
+       MONO_EMIT_NEW_COMPARE_BRANCH_BLOCK_CHAINED (s, CEE_BNE_UN, state->left->left->reg2, state->left->right->reg2, tree->inst_false_bb);
+       MONO_EMIT_NEW_COMPARE_BRANCH_BLOCK (s, CEE_BGT_UN, state->left->left->reg1, state->left->right->reg1, tree->inst_true_bb);
 }
 
 stmt: CEE_BGT (OP_LCOMPARE (lreg, i8con)) {
-
-       MONO_EMIT_NEW_BIALU_IMM (s, OP_COMPARE_IMM, -1, state->left->left->reg2, state->left->right->tree->inst_ms_word);
-       MONO_EMIT_NEW_BRANCH_BLOCK (s, CEE_BGT, tree->inst_true_bb);
-       MONO_EMIT_NEW_BRANCH_BLOCK (s, CEE_BNE_UN, tree->inst_false_bb);
-       MONO_EMIT_NEW_BIALU_IMM (s, OP_COMPARE_IMM, -1, state->left->left->reg1, state->left->right->tree->inst_ls_word);
-       MONO_EMIT_NEW_BRANCH_BLOCK (s, CEE_BGT_UN, tree->inst_true_bb);
+       MONO_EMIT_NEW_COMPARE_IMM_BRANCH_BLOCK (s, CEE_BGT, state->left->left->reg2, state->left->right->tree->inst_ms_word, tree->inst_true_bb);
+       MONO_EMIT_NEW_COMPARE_IMM_BRANCH_BLOCK_CHAINED (s, CEE_BNE_UN, state->left->left->reg2, state->left->right->tree->inst_ms_word, tree->inst_false_bb);
+       MONO_EMIT_NEW_COMPARE_IMM_BRANCH_BLOCK (s, CEE_BGT_UN, state->left->left->reg1, state->left->right->tree->inst_ls_word, tree->inst_true_bb);
 }
 
 stmt: CEE_BGT_UN (OP_LCOMPARE (lreg, lreg)) {
-
-       MONO_EMIT_NEW_BIALU (s, OP_COMPARE, -1, state->left->left->reg2, state->left->right->reg2);
-       MONO_EMIT_NEW_BRANCH_BLOCK (s, CEE_BGT_UN, tree->inst_true_bb);
-       MONO_EMIT_NEW_BRANCH_BLOCK (s, CEE_BNE_UN, tree->inst_false_bb);
-       MONO_EMIT_NEW_BIALU (s, OP_COMPARE, -1, state->left->left->reg1, state->left->right->reg1);
-       MONO_EMIT_NEW_BRANCH_BLOCK (s, CEE_BGT_UN, tree->inst_true_bb);
+       MONO_EMIT_NEW_COMPARE_BRANCH_BLOCK (s, CEE_BGT_UN, state->left->left->reg2, state->left->right->reg2, tree->inst_true_bb);
+       MONO_EMIT_NEW_COMPARE_BRANCH_BLOCK_CHAINED (s, CEE_BNE_UN, state->left->left->reg2, state->left->right->reg2, tree->inst_false_bb);
+       MONO_EMIT_NEW_COMPARE_BRANCH_BLOCK (s, CEE_BGT_UN, state->left->left->reg1, state->left->right->reg1, tree->inst_true_bb);
 }
 
 stmt: CEE_BGT_UN (OP_LCOMPARE (lreg, i8con)) {
-
-       MONO_EMIT_NEW_BIALU_IMM (s, OP_COMPARE_IMM, -1, state->left->left->reg2, state->left->right->tree->inst_ms_word);
-       MONO_EMIT_NEW_BRANCH_BLOCK (s, CEE_BGT_UN, tree->inst_true_bb);
-       MONO_EMIT_NEW_BRANCH_BLOCK (s, CEE_BNE_UN, tree->inst_false_bb);
-       MONO_EMIT_NEW_BIALU_IMM (s, OP_COMPARE_IMM, -1, state->left->left->reg1, state->left->right->tree->inst_ls_word);
-       MONO_EMIT_NEW_BRANCH_BLOCK (s, CEE_BGT_UN, tree->inst_true_bb);
+       MONO_EMIT_NEW_COMPARE_IMM_BRANCH_BLOCK (s, CEE_BGT_UN, state->left->left->reg2, state->left->right->tree->inst_ms_word, tree->inst_true_bb);
+       MONO_EMIT_NEW_COMPARE_IMM_BRANCH_BLOCK_CHAINED (s, CEE_BNE_UN, state->left->left->reg2, state->left->right->tree->inst_ms_word, tree->inst_false_bb);
+       MONO_EMIT_NEW_COMPARE_IMM_BRANCH_BLOCK (s, CEE_BGT_UN, state->left->left->reg1, state->left->right->tree->inst_ls_word, tree->inst_true_bb);
 }
 
 lreg: CEE_CONV_I8 (OP_ICONST) {
@@ -646,8 +601,7 @@ lreg: CEE_CONV_U8 (reg) {
 }
 
 lreg: CEE_CONV_OVF_U8 (reg) {
-       MONO_EMIT_NEW_COMPARE_IMM (s, state->left->reg1, 0);
-       MONO_EMIT_NEW_COND_EXC (s, LT, "OverflowException");
+       MONO_EMIT_NEW_COMPARE_IMM_EXC (s, LT, state->left->reg1, 0, "OverflowException");
        MONO_EMIT_NEW_ICONST (s, state->reg2, 0);
        MONO_EMIT_UNALU (s, tree, OP_MOVE, state->reg1, state->left->reg1);
 }
@@ -669,6 +623,17 @@ lreg: CEE_CONV_OVF_U8_UN (reg) {
        MONO_EMIT_UNALU (s, tree, OP_MOVE, state->reg1, state->left->reg1);
 }
 
+reg: CEE_CONV_OVF_I_UN (reg),
+reg: CEE_CONV_OVF_U (reg) {
+       MONO_EMIT_NEW_COMPARE_IMM_EXC (s, LT, state->left->reg1, 0, "OverflowException");
+       MONO_EMIT_UNALU (s, tree, OP_MOVE, state->reg1, state->left->reg1);
+}
+
+reg: CEE_CONV_OVF_U_UN (reg),
+reg: CEE_CONV_OVF_I (reg) {
+       MONO_EMIT_UNALU (s, tree, OP_MOVE, state->reg1, state->left->reg1);
+}
+
 freg: OP_LCONV_TO_R_UN (lreg) {
        MONO_EMIT_BIALU (s, tree, tree->opcode, state->reg1, state->left->reg1, state->left->reg2);
 }
@@ -725,13 +690,9 @@ reg: OP_LCONV_TO_U2 (lreg) {
 }
 
 reg: OP_LCONV_TO_OVF_I1_UN (lreg) {
-       MONO_EMIT_NEW_BIALU_IMM (s, OP_COMPARE_IMM, -1, state->left->reg2, 0);
-       MONO_EMIT_NEW_COND_EXC (s, NE_UN, "OverflowException");
-
-       MONO_EMIT_NEW_COMPARE_IMM (s, state->left->reg1, 127);
-       MONO_EMIT_NEW_COND_EXC (s, GT, "OverflowException");
-       MONO_EMIT_NEW_COMPARE_IMM (s, state->left->reg1, -128);
-       MONO_EMIT_NEW_COND_EXC (s, LT, "OverflowException");
+       MONO_EMIT_NEW_COMPARE_IMM_EXC (s, NE_UN, state->left->reg2, 0, "OverflowException");
+       MONO_EMIT_NEW_COMPARE_IMM_EXC (s, GT, state->left->reg1, 127, "OverflowException");
+       MONO_EMIT_NEW_COMPARE_IMM_EXC (s, LT, state->left->reg1, -128, "OverflowException");
        MONO_EMIT_UNALU (s, tree, CEE_CONV_I1, state->reg1, state->left->reg1);
 }
 
@@ -741,23 +702,17 @@ reg: OP_LCONV_TO_OVF_I1 (lreg) {
        MONO_NEW_LABEL (s, is_negative);
        MONO_NEW_LABEL (s, end_label);
 
-       MONO_EMIT_NEW_BIALU_IMM (s, OP_COMPARE_IMM, -1, state->left->reg2, 0);
-       MONO_EMIT_NEW_COND_EXC (s, GT, "OverflowException");
-       MONO_EMIT_NEW_BIALU_IMM (s, OP_COMPARE_IMM, -1, state->left->reg2, -1);
-       MONO_EMIT_NEW_COND_EXC (s, LT, "OverflowException");
-
-       MONO_EMIT_NEW_BIALU_IMM (s, OP_COMPARE_IMM, -1, state->left->reg2, 0);
-       MONO_EMIT_NEW_BRANCH_LABEL (s, CEE_BLT, is_negative);
+       MONO_EMIT_NEW_COMPARE_IMM_EXC (s, GT, state->left->reg2, 0, "OverflowException");
+       MONO_EMIT_NEW_COMPARE_IMM_EXC (s, LT, state->left->reg2, -1, "OverflowException");
+       MONO_EMIT_NEW_COMPARE_IMM_BRANCH_LABEL (s, CEE_BLT, state->left->reg2, 0, is_negative);
 
        /* Positive */
-       MONO_EMIT_NEW_COMPARE_IMM (s, state->left->reg1, 127);
-       MONO_EMIT_NEW_COND_EXC (s, GT_UN, "OverflowException");
-       MONO_EMIT_NEW_BRANCH_LABEL (s, CEE_BR, end_label);
+       MONO_EMIT_NEW_COMPARE_IMM_EXC (s, GT_UN, state->left->reg1, 127, "OverflowException");
+       MONO_EMIT_NEW_BRANCH_LABEL (s, OP_BR, end_label);
 
        /* Negative */
        mono_bblock_add_inst (s->cbb, is_negative);
-       MONO_EMIT_NEW_COMPARE_IMM (s, state->left->reg1, -128);
-       MONO_EMIT_NEW_COND_EXC (s, LT_UN, "OverflowException");
+       MONO_EMIT_NEW_COMPARE_IMM_EXC (s, LT_UN, state->left->reg1, -128, "OverflowException");
        mono_bblock_add_inst (s->cbb, end_label);
 
        MONO_EMIT_UNALU (s, tree, CEE_CONV_I1, state->reg1, state->left->reg1);
@@ -765,12 +720,10 @@ reg: OP_LCONV_TO_OVF_I1 (lreg) {
 
 reg: OP_LCONV_TO_OVF_U1_UN (lreg),
 reg: OP_LCONV_TO_OVF_U1 (lreg) {
-       MONO_EMIT_NEW_BIALU_IMM (s, OP_COMPARE_IMM, -1, state->left->reg2, 0);
-       MONO_EMIT_NEW_COND_EXC (s, NE_UN, "OverflowException");
+       MONO_EMIT_NEW_COMPARE_IMM_EXC (s, NE_UN, state->left->reg2, 0, "OverflowException");
 
        /* probe value to be within 0 to 255 */
-       MONO_EMIT_NEW_COMPARE_IMM (s, state->left->reg1, 255);
-       MONO_EMIT_NEW_COND_EXC (s, GT_UN, "OverflowException");
+       MONO_EMIT_NEW_COMPARE_IMM_EXC (s, GT_UN, state->left->reg1, 255, "OverflowException");
        MONO_EMIT_BIALU_IMM (s, tree, OP_AND_IMM, state->reg1, state->left->reg1, 0xff);
 }
 
@@ -780,67 +733,56 @@ reg: OP_LCONV_TO_OVF_I2 (lreg) {
        MONO_NEW_LABEL (s, is_negative);
        MONO_NEW_LABEL (s, end_label);
 
-       MONO_EMIT_NEW_BIALU_IMM (s, OP_COMPARE_IMM, -1, state->left->reg2, 0);
-       MONO_EMIT_NEW_COND_EXC (s, GT, "OverflowException");
-       MONO_EMIT_NEW_BIALU_IMM (s, OP_COMPARE_IMM, -1, state->left->reg2, -1);
-       MONO_EMIT_NEW_COND_EXC (s, LT, "OverflowException");
+       MONO_EMIT_NEW_COMPARE_IMM_EXC (s, GT, state->left->reg2, 0, "OverflowException");
+       MONO_EMIT_NEW_COMPARE_IMM_EXC (s, LT, state->left->reg2, -1, "OverflowException");
 
-       MONO_EMIT_NEW_BIALU_IMM (s, OP_COMPARE_IMM, -1, state->left->reg2, 0);
-       MONO_EMIT_NEW_BRANCH_LABEL (s, CEE_BLT, is_negative);
+       MONO_EMIT_NEW_COMPARE_IMM_BRANCH_LABEL (s, CEE_BLT, state->left->reg2, 0, is_negative);
 
        /* Positive */
-       MONO_EMIT_NEW_COMPARE_IMM (s, state->left->reg1, 32767);
-       MONO_EMIT_NEW_COND_EXC (s, GT_UN, "OverflowException");
-       MONO_EMIT_NEW_BRANCH_LABEL (s, CEE_BR, end_label);
+       MONO_EMIT_NEW_COMPARE_IMM_EXC (s, GT_UN, state->left->reg1, 32767, "OverflowException");
+       MONO_EMIT_NEW_BRANCH_LABEL (s, OP_BR, end_label);
 
        /* Negative */
        mono_bblock_add_inst (s->cbb, is_negative);
-       MONO_EMIT_NEW_COMPARE_IMM (s, state->left->reg1, -32768);
-       MONO_EMIT_NEW_COND_EXC (s, LT_UN, "OverflowException");
+       MONO_EMIT_NEW_COMPARE_IMM_EXC (s, LT_UN, state->left->reg1, -32768, "OverflowException");
        mono_bblock_add_inst (s->cbb, end_label);
 
        MONO_EMIT_UNALU (s, tree, CEE_CONV_I2, state->reg1, state->left->reg1);
 }
 
 reg: OP_LCONV_TO_OVF_I2_UN (lreg) {
-       MONO_EMIT_NEW_BIALU_IMM (s, OP_COMPARE_IMM, -1, state->left->reg2, 0);
-       MONO_EMIT_NEW_COND_EXC (s, NE_UN, "OverflowException");
+       MONO_EMIT_NEW_COMPARE_IMM_EXC (s, NE_UN, state->left->reg2, 0, "OverflowException");
 
        /* Probe value to be within -32768 and 32767 */
-       MONO_EMIT_NEW_COMPARE_IMM (s, state->left->reg1, 32767);
-       MONO_EMIT_NEW_COND_EXC (s, GT, "OverflowException");
-       MONO_EMIT_NEW_COMPARE_IMM (s, state->left->reg1, -32768);
-       MONO_EMIT_NEW_COND_EXC (s, LT, "OverflowException");
+       MONO_EMIT_NEW_COMPARE_IMM_EXC (s, GT, state->left->reg1, 32767, "OverflowException");
+       MONO_EMIT_NEW_COMPARE_IMM_EXC (s, LT, state->left->reg1, -32768, "OverflowException");
        MONO_EMIT_UNALU (s, tree, CEE_CONV_I2, state->reg1, state->left->reg1);
 }
 
 reg: OP_LCONV_TO_OVF_U2_UN (lreg),
 reg: OP_LCONV_TO_OVF_U2 (lreg) {
-       MONO_EMIT_NEW_BIALU_IMM (s, OP_COMPARE_IMM, -1, state->left->reg2, 0);
-       MONO_EMIT_NEW_COND_EXC (s, NE_UN, "OverflowException");
+       MONO_EMIT_NEW_COMPARE_IMM_EXC (s, NE_UN, state->left->reg2, 0, "OverflowException");
 
        /* Probe value to be within 0 and 65535 */
-       MONO_EMIT_NEW_COMPARE_IMM (s, state->left->reg1, 0xffff);
-       MONO_EMIT_NEW_COND_EXC (s, GT_UN, "OverflowException");
+       MONO_EMIT_NEW_COMPARE_IMM_EXC (s, GT_UN, state->left->reg1, 0xffff, "OverflowException");
        MONO_EMIT_BIALU_IMM (s, tree, OP_AND_IMM, state->reg1, state->left->reg1, 0xffff);
 }
 
 
-reg: OP_LCONV_TO_OVF_U4_UN (lreg) {
-       MONO_EMIT_NEW_BIALU_IMM (s, OP_COMPARE_IMM, -1, state->left->reg2, 0);
-       MONO_EMIT_NEW_COND_EXC (s, NE_UN, "OverflowException");
+reg: OP_LCONV_TO_OVF_U4_UN (lreg),
+reg: OP_LCONV_TO_OVF_U_UN (lreg) {
+       MONO_EMIT_NEW_COMPARE_IMM_EXC (s, NE_UN, state->left->reg2, 0, "OverflowException");
        MONO_EMIT_UNALU (s, tree, OP_MOVE, state->reg1, state->left->reg1);
 }
 
 reg: OP_LCONV_TO_OVF_I_UN (lreg) {
-       MONO_EMIT_NEW_BIALU_IMM (s, OP_COMPARE_IMM, -1, state->left->reg2, 0);
-       MONO_EMIT_NEW_COND_EXC (s, NE_UN, "OverflowException");
+       MONO_EMIT_NEW_COMPARE_IMM_EXC (s, NE_UN, state->left->reg2, 0, "OverflowException");
        MONO_EMIT_UNALU (s, tree, OP_MOVE, state->reg1, state->left->reg1);
 }
 
-reg: OP_LCONV_TO_OVF_U4 (lreg) {
-       MONO_EMIT_NEW_BIALU_IMM (s, OP_COMPARE_IMM, -1, state->left->reg2, 0);
-       MONO_EMIT_NEW_COND_EXC (s, NE_UN, "OverflowException");
+reg: OP_LCONV_TO_OVF_U4 (lreg),
+reg: OP_LCONV_TO_OVF_U (lreg) {
+       MONO_EMIT_NEW_COMPARE_IMM_EXC (s, NE_UN, state->left->reg2, 0, "OverflowException");
        MONO_EMIT_UNALU (s, tree, OP_MOVE, state->reg1, state->left->reg1);
 }
 
@@ -852,10 +794,8 @@ reg: OP_LCONV_TO_OVF_I (lreg) {
 }
 
 reg: OP_LCONV_TO_OVF_I4_UN (lreg) {
-       MONO_EMIT_NEW_BIALU_IMM (s, OP_COMPARE_IMM, -1, state->left->reg2, 0);
-       MONO_EMIT_NEW_COND_EXC (s, NE_UN, "OverflowException");
-       MONO_EMIT_NEW_BIALU_IMM (s, OP_COMPARE_IMM, -1, state->left->reg1, 0);
-       MONO_EMIT_NEW_COND_EXC (s, LT, "OverflowException");
+       MONO_EMIT_NEW_COMPARE_IMM_EXC (s, NE_UN, state->left->reg2, 0, "OverflowException");
+       MONO_EMIT_NEW_COMPARE_IMM_EXC (s, LT, state->left->reg1, 0, "OverflowException");
        MONO_EMIT_NEW_UNALU (s, OP_MOVE, state->reg1, state->left->reg1);
 }
 
@@ -868,16 +808,14 @@ reg: OP_LCONV_TO_OVF_I4 (lreg) {
 }
 
 lreg: OP_LCONV_TO_OVF_I8_UN (lreg) {
-       MONO_EMIT_NEW_BIALU_IMM (s, OP_COMPARE_IMM, -1, state->left->reg2, 0);
-       MONO_EMIT_NEW_COND_EXC (s, LT, "OverflowException");
+       MONO_EMIT_NEW_COMPARE_IMM_EXC (s, LT, state->left->reg2, 0, "OverflowException");
 
        MONO_EMIT_NEW_UNALU (s, OP_MOVE, state->reg1, state->left->reg1);
        MONO_EMIT_UNALU (s, tree, OP_MOVE, state->reg2, state->left->reg2);
 }
 
 lreg: OP_LCONV_TO_OVF_U8 (lreg) {
-       MONO_EMIT_NEW_BIALU_IMM (s, OP_COMPARE_IMM, -1, state->left->reg2, 0);
-       MONO_EMIT_NEW_COND_EXC (s, LT, "OverflowException");
+       MONO_EMIT_NEW_COMPARE_IMM_EXC (s, LT, state->left->reg2, 0, "OverflowException");
 
        MONO_EMIT_NEW_UNALU (s, OP_MOVE, state->reg1, state->left->reg1);
        MONO_EMIT_UNALU (s, tree, OP_MOVE, state->reg2, state->left->reg2);
@@ -897,17 +835,37 @@ lreg: OP_LCALLVIRT (reg) {
        mini_emit_virtual_call (s, state, tree, OP_LCALL, OP_LCALL_MEMBASE);
 }
 
+lreg: OP_LCALLVIRT_IMT (reg, reg) {
+       tree->opcode = OP_LCALLVIRT;
+       mini_emit_virtual_imt_call (s, state, tree, OP_LCALL, OP_LCALL_MEMBASE, state->right->reg1);
+}
+
 lreg: OP_LCALL {
        tree->dreg = state->reg1;
        mono_bblock_add_inst (s->cbb, tree);
 }
 
+lreg: OP_LCALL_RGCTX (reg) {
+       emit_rgctx_argument (s, tree, state->left->reg1, OP_LCALL);
+
+       tree->dreg = state->reg1;
+       mono_bblock_add_inst (s->cbb, tree);
+}
+
 lreg: OP_LCALL_REG (reg) {
        tree->sreg1 = state->left->reg1;
        tree->dreg = state->reg1;
        mono_bblock_add_inst (s->cbb, tree);
 }
 
+lreg: OP_LCALL_REG_RGCTX (reg, reg) {
+       emit_rgctx_argument (s, tree, state->right->reg1, OP_LCALL_REG);
+
+       tree->sreg1 = state->left->reg1;
+       tree->dreg = state->reg1;
+       mono_bblock_add_inst (s->cbb, tree);
+}
+
 lreg: OP_LCALL_REG (OP_ICONST) {
        tree->opcode = OP_LCALL;
        ((MonoCallInst*)tree)->fptr = state->left->tree->inst_p0;