2008-08-28 Zoltan Varga <vargaz@gmail.com>
[mono.git] / mono / mini / inssel-long32-mips.brg
index 258df89d9b8b14ccd2b35a94b7221c3abbb2f8bd..cb2ac24b2874dc3fd19fc6603402599caeb9ac72 100644 (file)
@@ -272,37 +272,136 @@ reg: OP_LCONV_TO_U4 (OP_LONG_SHRUN_32 (CEE_LDIND_I8 (base))) {
 }
 
 lreg: OP_LADD (lreg, i8con) {
+       int tmp1 = mono_regstate_next_int (s->rs);
+
        MONO_EMIT_NEW_BIALU_IMM (s, OP_ADD_IMM, state->reg1, state->left->reg1, state->right->tree->inst_ls_word);
-       MONO_EMIT_NEW_BIALU (s, OP_MIPS_SLTU, mips_temp, state->reg1, state->left->reg1);
+       MONO_EMIT_NEW_BIALU (s, OP_MIPS_SLTU, tmp1, state->reg1, state->left->reg1);
        MONO_EMIT_NEW_BIALU_IMM (s, OP_ADD_IMM, state->reg2, state->left->reg2, state->right->tree->inst_ms_word);
-       MONO_EMIT_BIALU (s, tree, CEE_ADD, state->reg2, mips_temp, state->reg2);
+       MONO_EMIT_BIALU (s, tree, CEE_ADD, state->reg2, tmp1, state->reg2);
+}
+
+lreg: OP_LADD (lreg, lreg) {
+       int tmp1 = mono_regstate_next_int (s->rs);
+
+       MONO_EMIT_NEW_BIALU (s, CEE_ADD, state->reg1, state->left->reg1, state->right->reg1);
+       MONO_EMIT_NEW_BIALU (s, OP_MIPS_SLTU, tmp1, state->reg1, state->left->reg1);
+       MONO_EMIT_NEW_BIALU (s, CEE_ADD, state->reg2, state->left->reg2, state->right->reg2);
+       MONO_EMIT_BIALU (s, tree, CEE_ADD, state->reg2, tmp1, state->reg2);
+}
+
+lreg: OP_LADD_OVF (lreg, lreg) {
+       int tmp1 = mono_regstate_next_int (s->rs);
+       int tmp2 = mono_regstate_next_int (s->rs);
+       int tmp3 = mono_regstate_next_int (s->rs);
+       int tmp4 = mono_regstate_next_int (s->rs);
+       int tmp5 = mono_regstate_next_int (s->rs);
+
+       MONO_EMIT_NEW_BIALU (s, CEE_ADD, state->reg1, state->left->reg1, state->right->reg1);
+
+       /* tmp1 holds the carry from the low 32-bit to the high 32-bits */
+
+       MONO_EMIT_NEW_BIALU (s, OP_MIPS_SLTU, tmp5, state->reg1, state->left->reg1);
+
+       /* add the high 32-bits, and add in the carry from the low 32-bits */
+
+       MONO_EMIT_NEW_BIALU (s, CEE_ADD, state->reg2, state->left->reg2, state->right->reg2);
+       MONO_EMIT_NEW_BIALU (s, CEE_ADD, state->reg2, tmp5, state->reg2);
+
+       /* Overflow happens if
+        *      neg + neg = pos    or
+        *      pos + pos = neg
+        * XOR of the high bits returns 0 if the signs match
+        * XOR of that with the high bit of the result return 1 if overflow.
+        */
+
+       /* tmp1 = 0 if the signs of the two inputs match, 1 otherwise */
+       MONO_EMIT_NEW_BIALU (s, CEE_XOR, tmp1, state->left->reg2, state->right->reg2);
+
+       /* set tmp2 = 0 if bit31 of results matches is different than the operands */
+       MONO_EMIT_NEW_BIALU (s, CEE_XOR, tmp2, state->reg2, state->right->reg2);
+       MONO_EMIT_NEW_UNALU (s, CEE_NOT, tmp2, tmp2);
+
+       /* OR(tmp1, tmp2) = 0 if both conditions are true */
+       MONO_EMIT_NEW_BIALU (s, CEE_OR, tmp3, tmp2, tmp1);
+
+       MONO_EMIT_NEW_BIALU_IMM (s, OP_SHR_IMM, tmp4, tmp3, 31);
+
+       /* Now, if (tmp4 == 0) then overflow */
+       MONO_EMIT_NEW_COMPARE_EXC (s, EQ, tmp4, mips_zero, "OverflowException");
 }
 
-lreg: OP_LADD (lreg, lreg),
-lreg: OP_LADD_OVF (lreg, lreg),
 lreg: OP_LADD_OVF_UN (lreg, lreg) {
+       int tmp1 = mono_regstate_next_int (s->rs);
+       int tmp2 = mono_regstate_next_int (s->rs);
+
        MONO_EMIT_NEW_BIALU (s, CEE_ADD, state->reg1, state->left->reg1, state->right->reg1);
-       MONO_EMIT_NEW_BIALU (s, OP_MIPS_SLTU, mips_at, state->reg1, state->left->reg1);
-       /* MONO_EMIT_NEW_COND_EXC (s, OV, "OverflowException"); */
+       MONO_EMIT_NEW_BIALU (s, OP_MIPS_SLTU, tmp1, state->reg1, state->left->reg1);
        MONO_EMIT_NEW_BIALU (s, CEE_ADD, state->reg2, state->left->reg2, state->right->reg2);
-       MONO_EMIT_BIALU (s, tree, CEE_ADD, state->reg2, mips_at, state->reg2);
+       MONO_EMIT_NEW_BIALU (s, CEE_ADD, state->reg2, tmp1, state->reg2);
+       MONO_EMIT_NEW_BIALU (s, OP_MIPS_SLTU, tmp2, state->reg2, state->left->reg2);
+       MONO_EMIT_NEW_COMPARE_EXC (s, NE_UN, tmp2, mips_zero, "OverflowException");
 }
 
 lreg: OP_LSUB (lreg, i8con) {
+       int tmp1 = mono_regstate_next_int (s->rs);
+
        MONO_EMIT_NEW_BIALU_IMM (s, OP_SUB_IMM, state->reg1, state->left->reg1, state->right->tree->inst_ls_word);
-       MONO_EMIT_NEW_BIALU (s, OP_MIPS_SLTU, mips_temp, state->left->reg1, state->reg1);
+       MONO_EMIT_NEW_BIALU (s, OP_MIPS_SLTU, tmp1, state->left->reg1, state->reg1);
        MONO_EMIT_NEW_BIALU_IMM (s, OP_SUB_IMM, state->reg2, state->left->reg2, state->right->tree->inst_ms_word);
-       MONO_EMIT_BIALU (s, tree, CEE_SUB, state->reg2, state->reg2, mips_temp);
+       MONO_EMIT_BIALU (s, tree, CEE_SUB, state->reg2, state->reg2, tmp1);
+}
+
+lreg: OP_LSUB (lreg, lreg) {
+       int tmp1 = mono_regstate_next_int (s->rs);
+
+       MONO_EMIT_NEW_BIALU (s, CEE_SUB, state->reg1, state->left->reg1, state->right->reg1);
+       MONO_EMIT_NEW_BIALU (s, OP_MIPS_SLTU, tmp1, state->left->reg1, state->reg1);
+       MONO_EMIT_NEW_BIALU (s, CEE_SUB, state->reg2, state->left->reg2, state->right->reg2);
+       MONO_EMIT_BIALU (s, tree, CEE_SUB, state->reg2, state->reg2, tmp1);
+}
+
+lreg: OP_LSUB_OVF (lreg, lreg) {
+       int tmp1 = mono_regstate_next_int (s->rs);
+       int tmp2 = mono_regstate_next_int (s->rs);
+       int tmp3 = mono_regstate_next_int (s->rs);
+       int tmp4 = mono_regstate_next_int (s->rs);
+       int tmp5 = mono_regstate_next_int (s->rs);
+
+       MONO_EMIT_NEW_BIALU (s, CEE_SUB, state->reg1, state->left->reg1, state->right->reg1);
+       MONO_EMIT_NEW_BIALU (s, OP_MIPS_SLTU, tmp5, state->left->reg1, state->reg1);
+       MONO_EMIT_NEW_BIALU (s, CEE_SUB, state->reg2, state->left->reg2, state->right->reg2);
+       MONO_EMIT_NEW_BIALU (s, CEE_SUB, state->reg2, state->reg2, tmp5);
+
+       /* Overflow happens if
+        *      neg - pos = pos    or
+        *      pos - neg = neg
+        * XOR of bit31 of the lhs & rhs = 1 if the signs are different
+        *
+        * tmp1 = (lhs ^ rhs)
+        * tmp2 = (lhs ^ result)
+        * if ((tmp1 < 0) & (tmp2 < 0)) then overflow
+        */
+
+       MONO_EMIT_NEW_BIALU (s, CEE_XOR, tmp1, state->left->reg2, state->right->reg2);
+       MONO_EMIT_NEW_BIALU (s, CEE_XOR, tmp2, state->left->reg2, state->reg2);
+       MONO_EMIT_NEW_BIALU (s, CEE_AND, tmp3, tmp2, tmp1);
+       MONO_EMIT_NEW_BIALU_IMM (s, OP_SHR_IMM, tmp4, tmp3, 31);
+
+       /* Now, if (tmp4 == 1) then overflow */
+       MONO_EMIT_NEW_COMPARE_EXC (s, NE_UN, tmp4, mips_zero, "OverflowException");
 }
 
-lreg: OP_LSUB (lreg, lreg),
-lreg: OP_LSUB_OVF (lreg, lreg),
 lreg: OP_LSUB_OVF_UN (lreg, lreg) {
+       int tmp1 = mono_regstate_next_int (s->rs);
+       int tmp2 = mono_regstate_next_int (s->rs);
+
        MONO_EMIT_NEW_BIALU (s, CEE_SUB, state->reg1, state->left->reg1, state->right->reg1);
-       MONO_EMIT_NEW_BIALU (s, OP_MIPS_SLTU, mips_at, state->left->reg1, state->reg1);
-       /* MONO_EMIT_NEW_COND_EXC (s, OV, "OverflowException"); */
+       MONO_EMIT_NEW_BIALU (s, OP_MIPS_SLTU, tmp1, state->left->reg1, state->reg1);
        MONO_EMIT_NEW_BIALU (s, CEE_SUB, state->reg2, state->left->reg2, state->right->reg2);
-       MONO_EMIT_BIALU (s, tree, CEE_SUB, state->reg2, state->reg2, mips_at);
+       MONO_EMIT_NEW_BIALU (s, CEE_SUB, state->reg2, state->reg2, tmp1);
+
+       MONO_EMIT_NEW_BIALU (s, OP_MIPS_SLTU, tmp2, state->left->reg2, state->reg2);
+       MONO_EMIT_NEW_COMPARE_EXC (s, NE_UN, tmp2, mips_zero, "OverflowException");
 }
 
 lreg: OP_LAND (lreg, lreg) {   
@@ -506,15 +605,14 @@ stmt: CEE_BLE (OP_LCOMPARE (lreg, lreg)) {
        MONO_EMIT_NEW_BIALU (s, OP_MIPS_SLT, mips_at, lreg2, rreg2);
        MONO_EMIT_NEW_COMPARE_BRANCH_BLOCK (s, OP_MIPS_BNE, mips_at, mips_zero, tree->inst_true_bb);
 
-       /* if (rreg2 < lreg2) -> false */
-       MONO_EMIT_NEW_BIALU (s, OP_MIPS_SLT, mips_at, rreg2, lreg2);
-       MONO_EMIT_NEW_COMPARE_BRANCH_BLOCK (s, OP_MIPS_BNE, mips_at, mips_zero, tree->inst_false_bb);
+       /* if (lreg2 != rreg2) -> false */
+       MONO_EMIT_NEW_COMPARE_BRANCH_BLOCK (s, OP_MIPS_BNE, lreg2, rreg2, tree->inst_false_bb);
 
        /* (lreg2 == rreg2), if (lreg1 <= rreg1) -> true  [or if (rreg1 < lreg1) -> false] */
 
        MONO_EMIT_NEW_BIALU (s, OP_MIPS_SLTU, mips_at, rreg1, lreg1);
        MONO_EMIT_NEW_COMPARE_BRANCH_BLOCK (s, OP_MIPS_BNE, mips_at, mips_zero, tree->inst_false_bb);
-       MONO_EMIT_NEW_BRANCH_BLOCK (s, CEE_BR, tree->inst_true_bb);
+       MONO_EMIT_NEW_BRANCH_BLOCK (s, OP_BR, tree->inst_true_bb);
 }
 
 stmt: CEE_BLE (OP_LCOMPARE (lreg, i8con)) {
@@ -529,16 +627,15 @@ stmt: CEE_BLE (OP_LCOMPARE (lreg, i8con)) {
        MONO_EMIT_NEW_BIALU (s, OP_MIPS_SLT, mips_at, lreg2, rreg2);
        MONO_EMIT_NEW_COMPARE_BRANCH_BLOCK (s, OP_MIPS_BNE, mips_at, mips_zero, tree->inst_true_bb);
 
-       /* if (rreg2 < lreg2) -> false */
-       MONO_EMIT_NEW_BIALU (s, OP_MIPS_SLT, mips_at, rreg2, lreg2);
-       MONO_EMIT_NEW_COMPARE_BRANCH_BLOCK (s, OP_MIPS_BNE, mips_at, mips_zero, tree->inst_false_bb);
+       /* if (lreg2 != rreg2) -> false */
+       MONO_EMIT_NEW_COMPARE_BRANCH_BLOCK (s, OP_MIPS_BNE, lreg2, rreg2, tree->inst_false_bb);
 
        /* (rreg2 == lreg2), if (lreg1 <= rreg1) -> true  [or if (rreg1 < lreg1) -> false] */
 
        MONO_EMIT_NEW_ICONST (s, rreg1, state->left->right->tree->inst_ls_word);
        MONO_EMIT_NEW_BIALU (s, OP_MIPS_SLTU, mips_at, rreg1, lreg1);
        MONO_EMIT_NEW_COMPARE_BRANCH_BLOCK (s, OP_MIPS_BNE, mips_at, mips_zero, tree->inst_false_bb);
-       MONO_EMIT_NEW_BRANCH_BLOCK (s, CEE_BR, tree->inst_true_bb);
+       MONO_EMIT_NEW_BRANCH_BLOCK (s, OP_BR, tree->inst_true_bb);
 }
 
 stmt: CEE_BLE_UN (OP_LCOMPARE (lreg, lreg)) {
@@ -551,15 +648,14 @@ stmt: CEE_BLE_UN (OP_LCOMPARE (lreg, lreg)) {
        MONO_EMIT_NEW_BIALU (s, OP_MIPS_SLTU, mips_at, lreg2, rreg2);
        MONO_EMIT_NEW_COMPARE_BRANCH_BLOCK (s, OP_MIPS_BNE, mips_at, mips_zero, tree->inst_true_bb);
 
-       /* if (rreg2 < lreg2) -> false */
-       MONO_EMIT_NEW_BIALU (s, OP_MIPS_SLTU, mips_at, rreg2, lreg2);
-       MONO_EMIT_NEW_COMPARE_BRANCH_BLOCK (s, OP_MIPS_BNE, mips_at, mips_zero, tree->inst_false_bb);
+       /* if (lreg2 != rreg2) -> false */
+       MONO_EMIT_NEW_COMPARE_BRANCH_BLOCK (s, OP_MIPS_BNE, lreg2, rreg2, tree->inst_false_bb);
 
        /* (lreg2 == rreg2), if (lreg1 <= rreg1) -> true  [or if (rreg1 < lreg1) -> false] */
 
        MONO_EMIT_NEW_BIALU (s, OP_MIPS_SLTU, mips_at, rreg1, lreg1);
        MONO_EMIT_NEW_COMPARE_BRANCH_BLOCK (s, OP_MIPS_BNE, mips_at, mips_zero, tree->inst_false_bb);
-       MONO_EMIT_NEW_BRANCH_BLOCK (s, CEE_BR, tree->inst_true_bb);
+       MONO_EMIT_NEW_BRANCH_BLOCK (s, OP_BR, tree->inst_true_bb);
 }
 
 stmt: CEE_BLE_UN (OP_LCOMPARE (lreg, i8con)) {
@@ -574,16 +670,15 @@ stmt: CEE_BLE_UN (OP_LCOMPARE (lreg, i8con)) {
        MONO_EMIT_NEW_BIALU (s, OP_MIPS_SLTU, mips_at, lreg2, rreg2);
        MONO_EMIT_NEW_COMPARE_BRANCH_BLOCK (s, OP_MIPS_BNE, mips_at, mips_zero, tree->inst_true_bb);
 
-       /* if (rreg2 < lreg2) -> false */
-       MONO_EMIT_NEW_BIALU (s, OP_MIPS_SLTU, mips_at, rreg2, lreg2);
-       MONO_EMIT_NEW_COMPARE_BRANCH_BLOCK (s, OP_MIPS_BNE, mips_at, mips_zero, tree->inst_false_bb);
+       /* if (lreg2 != rreg2) -> false */
+       MONO_EMIT_NEW_COMPARE_BRANCH_BLOCK (s, OP_MIPS_BNE, lreg2, rreg2, tree->inst_false_bb);
 
        /* (rreg2 == lreg2), if (rreg1 <= lreg1) -> true  [or if (rreg1 < lreg1) -> false] */
 
        MONO_EMIT_NEW_ICONST (s, rreg1, state->left->right->tree->inst_ls_word);
        MONO_EMIT_NEW_BIALU (s, OP_MIPS_SLTU, mips_at, rreg1, lreg1);
        MONO_EMIT_NEW_COMPARE_BRANCH_BLOCK (s, OP_MIPS_BNE, mips_at, mips_zero, tree->inst_false_bb);
-       MONO_EMIT_NEW_BRANCH_BLOCK (s, CEE_BR, tree->inst_true_bb);
+       MONO_EMIT_NEW_BRANCH_BLOCK (s, OP_BR, tree->inst_true_bb);
 }
 
 stmt: CEE_BGE (OP_LCOMPARE (lreg, lreg)) {
@@ -596,13 +691,13 @@ stmt: CEE_BGE (OP_LCOMPARE (lreg, lreg)) {
        MONO_EMIT_NEW_BIALU (s, OP_MIPS_SLT, mips_at, lreg2, rreg2);
        MONO_EMIT_NEW_COMPARE_BRANCH_BLOCK (s, OP_MIPS_BNE, mips_at, mips_zero, tree->inst_false_bb);
 
-       /* if (rreg2 != lreg2) -> false */
-       MONO_EMIT_NEW_COMPARE_BRANCH_BLOCK (s, OP_MIPS_BNE, rreg2, lreg2, tree->inst_false_bb);
+       /* if (lreg2 != rreg2) -> true */
+       MONO_EMIT_NEW_COMPARE_BRANCH_BLOCK (s, OP_MIPS_BNE, lreg2, rreg2, tree->inst_true_bb);
 
-       /* (rreg2 == lreg2), so if (lreg1 < rreg1) -> false */
-       MONO_EMIT_NEW_BIALU (s, OP_MIPS_SLT, mips_at, lreg1, rreg1);
+       /* (lreg2 == rreg2), so if (lreg1 < rreg1) -> false */
+       MONO_EMIT_NEW_BIALU (s, OP_MIPS_SLTU, mips_at, lreg1, rreg1);
        MONO_EMIT_NEW_COMPARE_BRANCH_BLOCK (s, OP_MIPS_BNE, mips_at, mips_zero, tree->inst_false_bb);
-       MONO_EMIT_NEW_BRANCH_BLOCK (s, CEE_BR, tree->inst_true_bb);
+       MONO_EMIT_NEW_BRANCH_BLOCK (s, OP_BR, tree->inst_true_bb);
 }
 
 stmt: CEE_BGE (OP_LCOMPARE (lreg, i8con)) {
@@ -617,15 +712,15 @@ stmt: CEE_BGE (OP_LCOMPARE (lreg, i8con)) {
        MONO_EMIT_NEW_BIALU (s, OP_MIPS_SLT, mips_at, lreg2, rreg2);
        MONO_EMIT_NEW_COMPARE_BRANCH_BLOCK (s, OP_MIPS_BNE, mips_at, mips_zero, tree->inst_false_bb);
 
-       /* if (rreg2 != lreg2) -> false */
-       MONO_EMIT_NEW_COMPARE_BRANCH_BLOCK (s, OP_MIPS_BNE, rreg2, lreg2, tree->inst_false_bb);
+       /* if (lreg2 != rreg2) -> true */
+       MONO_EMIT_NEW_COMPARE_BRANCH_BLOCK (s, OP_MIPS_BNE, lreg2, rreg2, tree->inst_true_bb);
 
        MONO_EMIT_NEW_ICONST (s, rreg1, state->left->right->tree->inst_ls_word);
 
-       /* (rreg2 == lreg2), so if (lreg1 < rreg1) -> false */
-       MONO_EMIT_NEW_BIALU (s, OP_MIPS_SLT, mips_at, lreg1, rreg1);
+       /* (lreg2 == rreg2), so if (lreg1 < rreg1) -> false */
+       MONO_EMIT_NEW_BIALU (s, OP_MIPS_SLTU, mips_at, lreg1, rreg1);
        MONO_EMIT_NEW_COMPARE_BRANCH_BLOCK (s, OP_MIPS_BNE, mips_at, mips_zero, tree->inst_false_bb);
-       MONO_EMIT_NEW_BRANCH_BLOCK (s, CEE_BR, tree->inst_true_bb);
+       MONO_EMIT_NEW_BRANCH_BLOCK (s, OP_BR, tree->inst_true_bb);
 }
 
 stmt: CEE_BGE_UN (OP_LCOMPARE (lreg, lreg)) {
@@ -638,13 +733,13 @@ stmt: CEE_BGE_UN (OP_LCOMPARE (lreg, lreg)) {
        MONO_EMIT_NEW_BIALU (s, OP_MIPS_SLTU, mips_at, lreg2, rreg2);
        MONO_EMIT_NEW_COMPARE_BRANCH_BLOCK (s, OP_MIPS_BNE, mips_at, mips_zero, tree->inst_false_bb);
 
-       /* if (rreg2 != lreg2) -> false */
-       MONO_EMIT_NEW_COMPARE_BRANCH_BLOCK (s, OP_MIPS_BNE, rreg2, lreg2, tree->inst_false_bb);
+       /* if (lreg2 != rreg2) -> true */
+       MONO_EMIT_NEW_COMPARE_BRANCH_BLOCK (s, OP_MIPS_BNE, lreg2, rreg2, tree->inst_true_bb);
 
        /* (rreg2 == lreg2), so if (lreg1 < rreg1) -> false */
-       MONO_EMIT_NEW_BIALU (s, OP_MIPS_SLT, mips_at, lreg1, rreg1);
+       MONO_EMIT_NEW_BIALU (s, OP_MIPS_SLTU, mips_at, lreg1, rreg1);
        MONO_EMIT_NEW_COMPARE_BRANCH_BLOCK (s, OP_MIPS_BNE, mips_at, mips_zero, tree->inst_false_bb);
-       MONO_EMIT_NEW_BRANCH_BLOCK (s, CEE_BR, tree->inst_true_bb);
+       MONO_EMIT_NEW_BRANCH_BLOCK (s, OP_BR, tree->inst_true_bb);
 }
 
 stmt: CEE_BGE_UN (OP_LCOMPARE (lreg, i8con)) {
@@ -659,15 +754,15 @@ stmt: CEE_BGE_UN (OP_LCOMPARE (lreg, i8con)) {
        MONO_EMIT_NEW_BIALU (s, OP_MIPS_SLTU, mips_at, lreg2, rreg2);
        MONO_EMIT_NEW_COMPARE_BRANCH_BLOCK (s, OP_MIPS_BNE, mips_at, mips_zero, tree->inst_false_bb);
 
-       /* if (rreg2 != lreg2) -> false */
-       MONO_EMIT_NEW_COMPARE_BRANCH_BLOCK (s, OP_MIPS_BNE, rreg2, lreg2, tree->inst_false_bb);
+       /* if (lreg2 != rreg2) -> true */
+       MONO_EMIT_NEW_COMPARE_BRANCH_BLOCK (s, OP_MIPS_BNE, lreg2, rreg2, tree->inst_true_bb);
 
        MONO_EMIT_NEW_ICONST (s, rreg1, state->left->right->tree->inst_ls_word);
 
-       /* (rreg2 == lreg2), so if (lreg1 < rreg1) -> false */
-       MONO_EMIT_NEW_BIALU (s, OP_MIPS_SLT, mips_at, lreg1, rreg1);
+       /* (lreg2 == rreg2), so if (lreg1 < rreg1) -> false */
+       MONO_EMIT_NEW_BIALU (s, OP_MIPS_SLTU, mips_at, lreg1, rreg1);
        MONO_EMIT_NEW_COMPARE_BRANCH_BLOCK (s, OP_MIPS_BNE, mips_at, mips_zero, tree->inst_false_bb);
-       MONO_EMIT_NEW_BRANCH_BLOCK (s, CEE_BR, tree->inst_true_bb);
+       MONO_EMIT_NEW_BRANCH_BLOCK (s, OP_BR, tree->inst_true_bb);
 }
 
 stmt: CEE_BLT (OP_LCOMPARE (lreg, lreg)) {
@@ -680,14 +775,13 @@ stmt: CEE_BLT (OP_LCOMPARE (lreg, lreg)) {
        MONO_EMIT_NEW_BIALU (s, OP_MIPS_SLT, mips_at, lreg2, rreg2);
        MONO_EMIT_NEW_COMPARE_BRANCH_BLOCK (s, OP_MIPS_BNE, mips_at, mips_zero, tree->inst_true_bb);
 
-       /* if (rreg2 < lreg2) -> false */
-       MONO_EMIT_NEW_BIALU (s, OP_MIPS_SLT, mips_at, rreg2, lreg2);
-       MONO_EMIT_NEW_COMPARE_BRANCH_BLOCK (s, OP_MIPS_BNE, mips_at, mips_zero, tree->inst_false_bb);
+       /* if (lreg2 != rreg2) -> false */
+       MONO_EMIT_NEW_COMPARE_BRANCH_BLOCK (s, OP_MIPS_BNE, lreg2, rreg2, tree->inst_false_bb);
 
        /* (lreg2 == rreg2), if (lreg1 < rreg1) -> true */
        MONO_EMIT_NEW_BIALU (s, OP_MIPS_SLTU, mips_at, lreg1, rreg1);
        MONO_EMIT_NEW_COMPARE_BRANCH_BLOCK (s, OP_MIPS_BNE, mips_at, mips_zero, tree->inst_true_bb);
-       MONO_EMIT_NEW_BRANCH_BLOCK (s, CEE_BR, tree->inst_false_bb);
+       MONO_EMIT_NEW_BRANCH_BLOCK (s, OP_BR, tree->inst_false_bb);
 }
 
 stmt: CEE_BLT (OP_LCOMPARE (lreg, i8con)) {
@@ -702,16 +796,15 @@ stmt: CEE_BLT (OP_LCOMPARE (lreg, i8con)) {
        MONO_EMIT_NEW_BIALU (s, OP_MIPS_SLT, mips_at, lreg2, rreg2);
        MONO_EMIT_NEW_COMPARE_BRANCH_BLOCK (s, OP_MIPS_BNE, mips_at, mips_zero, tree->inst_true_bb);
 
-       /* if (rreg2 < lreg2) -> false */
-       MONO_EMIT_NEW_BIALU (s, OP_MIPS_SLT, mips_at, rreg2, lreg2);
-       MONO_EMIT_NEW_COMPARE_BRANCH_BLOCK (s, OP_MIPS_BNE, mips_at, mips_zero, tree->inst_false_bb);
+       /* if (lreg2 != rreg2) -> false */
+       MONO_EMIT_NEW_COMPARE_BRANCH_BLOCK (s, OP_MIPS_BNE, lreg2, rreg2, tree->inst_false_bb);
 
        MONO_EMIT_NEW_ICONST (s, rreg1, state->left->right->tree->inst_ls_word);
 
        /* (lreg2 == rreg2), if (lreg1 < rreg1) -> true */
        MONO_EMIT_NEW_BIALU (s, OP_MIPS_SLTU, mips_at, lreg1, rreg1);
        MONO_EMIT_NEW_COMPARE_BRANCH_BLOCK (s, OP_MIPS_BNE, mips_at, mips_zero, tree->inst_true_bb);
-       MONO_EMIT_NEW_BRANCH_BLOCK (s, CEE_BR, tree->inst_false_bb);
+       MONO_EMIT_NEW_BRANCH_BLOCK (s, OP_BR, tree->inst_false_bb);
 }
 
 stmt: CEE_BLT_UN (OP_LCOMPARE (lreg, lreg)) {
@@ -724,14 +817,13 @@ stmt: CEE_BLT_UN (OP_LCOMPARE (lreg, lreg)) {
        MONO_EMIT_NEW_BIALU (s, OP_MIPS_SLTU, mips_at, lreg2, rreg2);
        MONO_EMIT_NEW_COMPARE_BRANCH_BLOCK (s, OP_MIPS_BNE, mips_at, mips_zero, tree->inst_true_bb);
 
-       /* if (rreg2 < lreg2) -> false */
-       MONO_EMIT_NEW_BIALU (s, OP_MIPS_SLTU, mips_at, rreg2, lreg2);
-       MONO_EMIT_NEW_COMPARE_BRANCH_BLOCK (s, OP_MIPS_BNE, mips_at, mips_zero, tree->inst_false_bb);
+       /* if (lreg2 != rreg2) -> false */
+       MONO_EMIT_NEW_COMPARE_BRANCH_BLOCK (s, OP_MIPS_BNE, lreg2, rreg2, tree->inst_false_bb);
 
        /* (lreg2 == rreg2), if (lreg1 < rreg1) -> true */
        MONO_EMIT_NEW_BIALU (s, OP_MIPS_SLTU, mips_at, lreg1, rreg1);
        MONO_EMIT_NEW_COMPARE_BRANCH_BLOCK (s, OP_MIPS_BNE, mips_at, mips_zero, tree->inst_true_bb);
-       MONO_EMIT_NEW_BRANCH_BLOCK (s, CEE_BR, tree->inst_false_bb);
+       MONO_EMIT_NEW_BRANCH_BLOCK (s, OP_BR, tree->inst_false_bb);
 }
 
 stmt: CEE_BLT_UN (OP_LCOMPARE (lreg, i8con)) {
@@ -746,16 +838,15 @@ stmt: CEE_BLT_UN (OP_LCOMPARE (lreg, i8con)) {
        MONO_EMIT_NEW_BIALU (s, OP_MIPS_SLTU, mips_at, lreg2, rreg2);
        MONO_EMIT_NEW_COMPARE_BRANCH_BLOCK (s, OP_MIPS_BNE, mips_at, mips_zero, tree->inst_true_bb);
 
-       /* if (rreg2 < lreg2) -> false */
-       MONO_EMIT_NEW_BIALU (s, OP_MIPS_SLTU, mips_at, rreg2, lreg2);
-       MONO_EMIT_NEW_COMPARE_BRANCH_BLOCK (s, OP_MIPS_BNE, mips_at, mips_zero, tree->inst_false_bb);
+       /* if (lreg2 != rreg2) -> false */
+       MONO_EMIT_NEW_COMPARE_BRANCH_BLOCK (s, OP_MIPS_BNE, lreg2, rreg2, tree->inst_false_bb);
 
        MONO_EMIT_NEW_ICONST (s, rreg1, state->left->right->tree->inst_ls_word);
 
        /* (lreg2 == rreg2), if (lreg1 < rreg1) -> true */
        MONO_EMIT_NEW_BIALU (s, OP_MIPS_SLTU, mips_at, lreg1, rreg1);
        MONO_EMIT_NEW_COMPARE_BRANCH_BLOCK (s, OP_MIPS_BNE, mips_at, mips_zero, tree->inst_true_bb);
-       MONO_EMIT_NEW_BRANCH_BLOCK (s, CEE_BR, tree->inst_false_bb);
+       MONO_EMIT_NEW_BRANCH_BLOCK (s, OP_BR, tree->inst_false_bb);
 }
 
 stmt: CEE_BGT (OP_LCOMPARE (lreg, lreg)) {
@@ -768,14 +859,13 @@ stmt: CEE_BGT (OP_LCOMPARE (lreg, lreg)) {
        MONO_EMIT_NEW_BIALU (s, OP_MIPS_SLT, mips_at, lreg2, rreg2);
        MONO_EMIT_NEW_COMPARE_BRANCH_BLOCK (s, OP_MIPS_BNE, mips_at, mips_zero, tree->inst_false_bb);
 
-       /* if (rreg2 < lreg2) -> true */
-       MONO_EMIT_NEW_BIALU (s, OP_MIPS_SLT, mips_at, rreg2, lreg2);
-       MONO_EMIT_NEW_COMPARE_BRANCH_BLOCK (s, OP_MIPS_BNE, mips_at, mips_zero, tree->inst_false_bb);
+       /* if (lreg2 != rreg2) -> true */
+       MONO_EMIT_NEW_COMPARE_BRANCH_BLOCK (s, OP_MIPS_BNE, lreg2, rreg2, tree->inst_true_bb);
 
        /* (rreg2 == lreg2), so if (lreg1 > rreg1) -> true */
        MONO_EMIT_NEW_BIALU (s, OP_MIPS_SLTU, mips_at, rreg1, lreg1);
        MONO_EMIT_NEW_COMPARE_BRANCH_BLOCK (s, OP_MIPS_BNE, mips_at, mips_zero, tree->inst_true_bb);
-       MONO_EMIT_NEW_BRANCH_BLOCK (s, CEE_BR, tree->inst_false_bb);
+       MONO_EMIT_NEW_BRANCH_BLOCK (s, OP_BR, tree->inst_false_bb);
 }
 
 stmt: CEE_BGT (OP_LCOMPARE (lreg, i8con)) {
@@ -790,16 +880,15 @@ stmt: CEE_BGT (OP_LCOMPARE (lreg, i8con)) {
        MONO_EMIT_NEW_BIALU (s, OP_MIPS_SLT, mips_at, lreg2, rreg2);
        MONO_EMIT_NEW_COMPARE_BRANCH_BLOCK (s, OP_MIPS_BNE, mips_at, mips_zero, tree->inst_false_bb);
 
-       /* if (rreg2 < lreg2) -> true */
-       MONO_EMIT_NEW_BIALU (s, OP_MIPS_SLT, mips_at, rreg2, lreg2);
-       MONO_EMIT_NEW_COMPARE_BRANCH_BLOCK (s, OP_MIPS_BNE, mips_at, mips_zero, tree->inst_false_bb);
+       /* if (lreg2 != rreg2) -> true */
+       MONO_EMIT_NEW_COMPARE_BRANCH_BLOCK (s, OP_MIPS_BNE, lreg2, rreg2, tree->inst_true_bb);
 
        MONO_EMIT_NEW_ICONST (s, rreg1, state->left->right->tree->inst_ls_word);
 
        /* (rreg2 == lreg2), so if (lreg1 > rreg1) -> true */
        MONO_EMIT_NEW_BIALU (s, OP_MIPS_SLTU, mips_at, rreg1, lreg1);
        MONO_EMIT_NEW_COMPARE_BRANCH_BLOCK (s, OP_MIPS_BNE, mips_at, mips_zero, tree->inst_true_bb);
-       MONO_EMIT_NEW_BRANCH_BLOCK (s, CEE_BR, tree->inst_false_bb);
+       MONO_EMIT_NEW_BRANCH_BLOCK (s, OP_BR, tree->inst_false_bb);
 }
 
 stmt: CEE_BGT_UN (OP_LCOMPARE (lreg, lreg)) {
@@ -812,14 +901,13 @@ stmt: CEE_BGT_UN (OP_LCOMPARE (lreg, lreg)) {
        MONO_EMIT_NEW_BIALU (s, OP_MIPS_SLTU, mips_at, lreg2, rreg2);
        MONO_EMIT_NEW_COMPARE_BRANCH_BLOCK (s, OP_MIPS_BNE, mips_at, mips_zero, tree->inst_false_bb);
 
-       /* if (rreg2 < lreg2) -> true */
-       MONO_EMIT_NEW_BIALU (s, OP_MIPS_SLTU, mips_at, rreg2, lreg2);
-       MONO_EMIT_NEW_COMPARE_BRANCH_BLOCK (s, OP_MIPS_BNE, mips_at, mips_zero, tree->inst_false_bb);
+       /* if (lreg2 != rreg2) -> true */
+       MONO_EMIT_NEW_COMPARE_BRANCH_BLOCK (s, OP_MIPS_BNE, lreg2, rreg2, tree->inst_true_bb);
 
        /* (rreg2 == lreg2), so if (lreg1 > rreg1) -> true */
        MONO_EMIT_NEW_BIALU (s, OP_MIPS_SLTU, mips_at, rreg1, lreg1);
        MONO_EMIT_NEW_COMPARE_BRANCH_BLOCK (s, OP_MIPS_BNE, mips_at, mips_zero, tree->inst_true_bb);
-       MONO_EMIT_NEW_BRANCH_BLOCK (s, CEE_BR, tree->inst_false_bb);
+       MONO_EMIT_NEW_BRANCH_BLOCK (s, OP_BR, tree->inst_false_bb);
 }
 
 stmt: CEE_BGT_UN (OP_LCOMPARE (lreg, i8con)) {
@@ -834,16 +922,15 @@ stmt: CEE_BGT_UN (OP_LCOMPARE (lreg, i8con)) {
        MONO_EMIT_NEW_BIALU (s, OP_MIPS_SLTU, mips_at, lreg2, rreg2);
        MONO_EMIT_NEW_COMPARE_BRANCH_BLOCK (s, OP_MIPS_BNE, mips_at, mips_zero, tree->inst_false_bb);
 
-       /* if (rreg2 < lreg2) -> true */
-       MONO_EMIT_NEW_BIALU (s, OP_MIPS_SLTU, mips_at, rreg2, lreg2);
-       MONO_EMIT_NEW_COMPARE_BRANCH_BLOCK (s, OP_MIPS_BNE, mips_at, mips_zero, tree->inst_false_bb);
+       /* if (lreg2 != rreg2) -> true */
+       MONO_EMIT_NEW_COMPARE_BRANCH_BLOCK (s, OP_MIPS_BNE, lreg2, rreg2, tree->inst_true_bb);
 
        MONO_EMIT_NEW_ICONST (s, rreg1, state->left->right->tree->inst_ls_word);
 
        /* (rreg2 == lreg2), so if (lreg1 > rreg1) -> true */
        MONO_EMIT_NEW_BIALU (s, OP_MIPS_SLTU, mips_at, rreg1, lreg1);
        MONO_EMIT_NEW_COMPARE_BRANCH_BLOCK (s, OP_MIPS_BNE, mips_at, mips_zero, tree->inst_true_bb);
-       MONO_EMIT_NEW_BRANCH_BLOCK (s, CEE_BR, tree->inst_false_bb);
+       MONO_EMIT_NEW_BRANCH_BLOCK (s, OP_BR, tree->inst_false_bb);
 }
 
 lreg: CEE_CONV_I8 (OP_ICONST) {
@@ -868,8 +955,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);
 }
@@ -947,13 +1033,10 @@ 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_EXC (s, NE_UN, state->left->reg2, 0, "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, 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);
 }
 
@@ -963,22 +1046,18 @@ 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_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_BRANCH_LABEL (s, CEE_BLT, state->left->reg2, mips_zero, 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);
@@ -986,12 +1065,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);
 }
 
@@ -1001,103 +1078,83 @@ 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_COMPARE_BRANCH_LABEL (s, CEE_BLT, state->left->reg2, mips_zero, 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");
+       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");
+       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 (lreg) {
-       tree->dreg = state->reg1;
-       tree->sreg1 = state->left->reg1;
-       tree->sreg2 = state->left->reg2;
-       mono_bblock_add_inst (s->cbb, tree);
-}
-
 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);
 }
 
+reg: OP_LCONV_TO_OVF_I (lreg),
 reg: OP_LCONV_TO_OVF_I4 (lreg) {
-       tree->dreg = state->reg1;
-       tree->sreg1 = state->left->reg1;
-       tree->sreg2 = state->left->reg2;
-       tree->opcode = OP_LCONV_TO_OVF_I;
-       mono_bblock_add_inst (s->cbb, tree);
+       int tmp_reg = mono_regstate_next_int (s->rs);
+
+       /* Overflows if reg2 != sign extension of reg1 */
+       MONO_EMIT_BIALU_IMM (s, tree, OP_SHR_IMM, tmp_reg, state->left->reg1, 31);
+
+       MONO_EMIT_NEW_COMPARE_EXC (s, NE_UN, state->left->reg2, tmp_reg, "OverflowException");
+       MONO_EMIT_NEW_UNALU (s, OP_MOVE, state->reg1, state->left->reg1);
 }
 
 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);
@@ -1122,12 +1179,27 @@ lreg: OP_LCALL {
        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;