* simple-cee-ops.h, simple-mini-ops.h: Fixed bug 78656.
[mono.git] / mono / mini / inssel-long32.brg
index 93fbf75d98d3a711b1f967782a1e5f33d007c05b..7d6d03c7853dbda581c3f655bdb7b3fe2d4798fd 100644 (file)
@@ -1,7 +1,7 @@
 %%
 
 #
-# inssel-long32.brg: burg file for 64bit instructions on 32bit architectures
+# inssel-long32.brg: burg file for integer instructions on 32bit architectures
 #
 # Author:
 #   Dietmar Maurer (dietmar@ximian.com)
@@ -9,6 +9,165 @@
 # (C) 2002 Ximian, Inc.
 #
 
+#
+# 32 bit rules
+#
+
+#
+# basic alu operations
+#
+
+reg: CEE_AND (reg, reg),
+reg: CEE_OR (reg, reg),
+reg: CEE_XOR (reg, reg),
+reg: CEE_ADD (reg, reg),
+reg: CEE_SUB (reg, reg),
+reg: CEE_MUL (reg, reg),
+reg: CEE_MUL_OVF (reg, reg),
+reg: CEE_MUL_OVF_UN (reg, reg),
+reg: CEE_DIV (reg, reg),
+reg: CEE_DIV_UN (reg, reg),
+reg: CEE_REM (reg, reg),
+reg: CEE_REM_UN (reg, reg),
+reg: CEE_SHL (reg, reg),
+reg: CEE_SHR (reg, reg),
+reg: CEE_SHR_UN (reg, reg) {
+       MONO_EMIT_BIALU (s, tree, tree->opcode, state->reg1, state->left->reg1, state->right->reg1);
+}
+
+reg: CEE_NEG (reg),
+reg: CEE_NOT (reg) {
+       MONO_EMIT_UNALU (s, tree, tree->opcode, state->reg1, state->left->reg1);
+}
+
+
+reg: CEE_AND (reg, OP_ICONST) {
+       MONO_EMIT_BIALU_IMM (s, tree, OP_AND_IMM, state->reg1, state->left->reg1, state->right->tree->inst_c0);
+}
+
+reg: CEE_OR (reg, OP_ICONST) {
+       MONO_EMIT_BIALU_IMM (s, tree, OP_OR_IMM, state->reg1, state->left->reg1, state->right->tree->inst_c0);
+}
+
+reg: CEE_XOR (reg, OP_ICONST) {
+       MONO_EMIT_BIALU_IMM (s, tree, OP_XOR_IMM, state->reg1, state->left->reg1, state->right->tree->inst_c0);
+}
+
+reg: CEE_ADD (reg, OP_ICONST) {
+       MONO_EMIT_BIALU_IMM (s, tree, OP_ADD_IMM, state->reg1, state->left->reg1, state->right->tree->inst_c0);
+}
+
+reg: CEE_SUB (reg, OP_ICONST) {
+       MONO_EMIT_BIALU_IMM (s, tree, OP_SUB_IMM, state->reg1, state->left->reg1, state->right->tree->inst_c0);
+}
+
+reg: CEE_MUL (reg, OP_ICONST) {
+       MONO_EMIT_BIALU_IMM (s, tree, OP_MUL_IMM, state->reg1, state->left->reg1, state->right->tree->inst_c0);
+}
+
+reg: CEE_SHL (reg, OP_ICONST) {
+       MONO_EMIT_BIALU_IMM (s, tree, OP_SHL_IMM, state->reg1, state->left->reg1, state->right->tree->inst_c0);
+}
+
+reg: CEE_SHR (reg, OP_ICONST) {
+       MONO_EMIT_BIALU_IMM (s, tree, OP_SHR_IMM, state->reg1, state->left->reg1, state->right->tree->inst_c0);
+}
+
+reg: CEE_SHR_UN (reg, OP_ICONST) {
+       MONO_EMIT_BIALU_IMM (s, tree, OP_SHR_UN_IMM, state->reg1, state->left->reg1, state->right->tree->inst_c0);
+}
+
+reg: CEE_ADD_OVF (reg, reg) {
+       MONO_EMIT_NEW_BIALU (s, OP_ADDCC, state->reg1, state->left->reg1, state->right->reg1);
+       MONO_EMIT_NEW_COND_EXC (s, OV, "OverflowException");
+}
+
+reg: CEE_ADD_OVF_UN (reg, reg) {
+       MONO_EMIT_NEW_BIALU (s, OP_ADDCC, state->reg1, state->left->reg1, state->right->reg1);
+       MONO_EMIT_NEW_COND_EXC (s, C, "OverflowException");
+}
+
+reg: CEE_SUB (reg, CEE_LDIND_I4 (OP_REGVAR)) {
+       MONO_EMIT_BIALU (s, tree, tree->opcode, state->reg1, state->left->reg1, state->right->left->tree->dreg);
+}
+
+reg: CEE_SUB_OVF (reg, reg) {
+       MONO_EMIT_NEW_BIALU (s, OP_SUBCC, state->reg1, state->left->reg1, state->right->reg1);
+       MONO_EMIT_NEW_COND_EXC (s, OV, "OverflowException");
+}
+
+reg: CEE_SUB_OVF_UN (reg, reg) {
+       MONO_EMIT_NEW_BIALU (s, OP_SUBCC, state->reg1, state->left->reg1, state->right->reg1);
+       MONO_EMIT_NEW_COND_EXC (s, C, "OverflowException");
+}
+
+cflags: OP_COMPARE (reg, reg) {
+       tree->sreg1 = state->left->reg1;
+       tree->sreg2 = state->right->reg1;
+       mono_bblock_add_inst (s->cbb, tree);
+}
+
+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) {
+       tree->sreg1 = state->left->left->tree->dreg;
+       tree->sreg2 = state->right->reg1;
+       mono_bblock_add_inst (s->cbb, tree);
+}
+
+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)) {
+       tree->sreg1 = state->left->left->tree->dreg;
+       tree->sreg2 = state->right->left->tree->dreg;
+       mono_bblock_add_inst (s->cbb, tree);
+}
+
+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) {
+       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) {
+       tree->opcode = OP_COMPARE_IMM;
+       tree->sreg1 = state->left->reg1;
+       tree->inst_imm = state->right->tree->inst_c0;
+       mono_bblock_add_inst (s->cbb, tree);
+}
+
+stmt: CEE_BNE_UN (cflags),
+stmt: CEE_BEQ (cflags),
+stmt: CEE_BLT (cflags),
+stmt: CEE_BLT_UN (cflags),
+stmt: CEE_BGT (cflags),
+stmt: CEE_BGT_UN (cflags),
+stmt: CEE_BGE  (cflags),
+stmt: CEE_BGE_UN (cflags),
+stmt: CEE_BLE  (cflags),
+stmt: CEE_BLE_UN (cflags) {
+       mono_bblock_add_inst (s->cbb, tree);
+}
+
+reg: OP_CEQ (cflags),
+reg: OP_CLT (cflags),
+reg: OP_CLT_UN (cflags),
+reg: OP_CGT (cflags),
+reg: OP_CGT_UN (cflags) {      
+       tree->dreg = state->reg1;
+       mono_bblock_add_inst (s->cbb, tree);
+}
+
+#
+# 64 bit rules
+#
+
 #
 # We use a new non-terminal called "lreg" for 64bit registers, and
 # emulate lreg with 2 32bit registers.
@@ -21,18 +180,18 @@ stmt: CEE_POP (lreg) {
 i8con: CEE_CONV_I8 (OP_ICONST) "0" {
        int data = state->left->tree->inst_c0;
        tree->opcode = OP_I8CONST;
-       tree->inst_c0 = data;
+       tree->inst_ls_word = data;
        if (data < 0)
-               tree->inst_c1 = -1;
+               tree->inst_ms_word = -1;
        else
-               tree->inst_c1 = 0;
+               tree->inst_ms_word = 0;
 }
 
 i8con: CEE_CONV_U8 (OP_ICONST) "0" {
        int data = state->left->tree->inst_c0;
        tree->opcode = OP_I8CONST;
-       tree->inst_c0 = data;
-       tree->inst_c1 = 0;
+       tree->inst_ls_word = data;
+       tree->inst_ms_word = 0;
 }
 
 i8con: OP_I8CONST "0"
@@ -49,76 +208,107 @@ lreg: OP_ICONST {
 }
 
 lreg: OP_I8CONST {
-       MONO_EMIT_NEW_ICONST (s, state->reg1, tree->inst_c0);
-       MONO_EMIT_NEW_ICONST (s, state->reg2, tree->inst_c1);
+       MONO_EMIT_NEW_ICONST (s, state->reg1, tree->inst_ls_word);
+       MONO_EMIT_NEW_ICONST (s, state->reg2, tree->inst_ms_word);
 }
 
 lreg: CEE_LDIND_I8 (base) {
        MONO_EMIT_NEW_LOAD_MEMBASE_OP (s, OP_LOADI4_MEMBASE, state->reg1, 
-                                      state->left->tree->inst_basereg, state->left->tree->inst_offset);
+                                      state->left->tree->inst_basereg, state->left->tree->inst_offset + MINI_LS_WORD_OFFSET);
        MONO_EMIT_NEW_LOAD_MEMBASE_OP (s, OP_LOADI4_MEMBASE, state->reg2, 
-                                      state->left->tree->inst_basereg, state->left->tree->inst_offset + 4);
+                                      state->left->tree->inst_basereg, state->left->tree->inst_offset + MINI_MS_WORD_OFFSET);
 }
 
 stmt: CEE_STIND_I8 (base, lreg) {
        MONO_EMIT_NEW_STORE_MEMBASE (s, OP_STOREI4_MEMBASE_REG, state->left->tree->inst_basereg,
-                                    state->left->tree->inst_offset + 4, state->right->reg2);
+                                    state->left->tree->inst_offset + MINI_MS_WORD_OFFSET, state->right->reg2);
        MONO_EMIT_NEW_STORE_MEMBASE (s, OP_STOREI4_MEMBASE_REG, state->left->tree->inst_basereg,
-                                    state->left->tree->inst_offset, state->right->reg1);
+                                    state->left->tree->inst_offset + MINI_LS_WORD_OFFSET, state->right->reg1);
 }
 
 stmt: CEE_STIND_I8 (base, i8con) {
        MONO_EMIT_NEW_STORE_MEMBASE_IMM (s, OP_STOREI4_MEMBASE_IMM, state->left->tree->inst_basereg,
-                                        state->left->tree->inst_offset + 4, state->right->tree->inst_c1);
+                                        state->left->tree->inst_offset + MINI_MS_WORD_OFFSET, state->right->tree->inst_ms_word);
        MONO_EMIT_NEW_STORE_MEMBASE_IMM (s, OP_STOREI4_MEMBASE_IMM, state->left->tree->inst_basereg,
-                                        state->left->tree->inst_offset, state->right->tree->inst_c0);
+                                        state->left->tree->inst_offset + MINI_LS_WORD_OFFSET, state->right->tree->inst_ls_word);
+}
+
+lreg: OP_BIGMUL (reg, reg),
+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) {
+       /* 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)) {
+       MONO_EMIT_NEW_UNALU (s, OP_MOVE, state->reg1, state->left->left->reg2);
+}
+
+
+lreg: OP_LONG_SHRUN_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))) {
+       /* 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,
+                                      state->left->left->left->tree->inst_offset + MINI_MS_WORD_OFFSET);
+}
 
 lreg: OP_LADD (lreg, lreg) {
-       MONO_EMIT_NEW_BIALU (s, CEE_ADD, state->reg1, state->left->reg1, state->right->reg1);
+       MONO_EMIT_NEW_BIALU (s, OP_ADDCC, state->reg1, state->left->reg1, state->right->reg1);
        MONO_EMIT_BIALU (s, tree, OP_ADC, state->reg2, state->left->reg2, state->right->reg2);
 }
 
 lreg: OP_LADD_OVF (lreg, lreg) {
        /* ADC sets the condition code */
-       MONO_EMIT_NEW_BIALU (s, CEE_ADD, state->reg1, state->left->reg1, state->right->reg1);
+       MONO_EMIT_NEW_BIALU (s, OP_ADDCC, state->reg1, state->left->reg1, state->right->reg1);
        MONO_EMIT_NEW_BIALU (s, OP_ADC, state->reg2, state->left->reg2, state->right->reg2);
        MONO_EMIT_NEW_COND_EXC (s, OV, "OverflowException");
 }
 
 lreg: OP_LADD_OVF_UN (lreg, lreg) {
        /* ADC sets the condition code */
-       MONO_EMIT_NEW_BIALU (s, CEE_ADD, state->reg1, state->left->reg1, state->right->reg1);
+       MONO_EMIT_NEW_BIALU (s, OP_ADDCC, state->reg1, state->left->reg1, state->right->reg1);
        MONO_EMIT_NEW_BIALU (s, OP_ADC, state->reg2, state->left->reg2, state->right->reg2);
        MONO_EMIT_NEW_COND_EXC (s, C, "OverflowException");
 }
 
 lreg: OP_LADD (lreg, i8con) {
-       MONO_EMIT_NEW_BIALU_IMM (s, OP_ADD_IMM, state->reg1, state->left->reg1, state->right->tree->inst_c0);
-       MONO_EMIT_BIALU_IMM (s, tree, OP_ADC_IMM, state->reg2, state->left->reg2, state->right->tree->inst_c1);
+       MONO_EMIT_NEW_BIALU_IMM (s, OP_ADDCC_IMM, state->reg1, state->left->reg1, state->right->tree->inst_ls_word);
+       MONO_EMIT_BIALU_IMM (s, tree, OP_ADC_IMM, state->reg2, state->left->reg2, state->right->tree->inst_ms_word);
 }
 
 lreg: OP_LSUB (lreg, lreg) {
-       MONO_EMIT_NEW_BIALU (s, CEE_SUB, state->reg1, state->left->reg1, state->right->reg1);
+       MONO_EMIT_NEW_BIALU (s, OP_SUBCC, state->reg1, state->left->reg1, state->right->reg1);
        MONO_EMIT_BIALU (s, tree, OP_SBB, state->reg2, state->left->reg2, state->right->reg2);
 }
 
 lreg: OP_LSUB (lreg, i8con) {
-       MONO_EMIT_NEW_BIALU_IMM (s, OP_SUB_IMM, state->reg1, state->left->reg1, state->right->tree->inst_c0);
-       MONO_EMIT_BIALU_IMM (s, tree, OP_SBB_IMM, state->reg2, state->left->reg2, state->right->tree->inst_c1);
+       MONO_EMIT_NEW_BIALU_IMM (s, OP_SUBCC_IMM, state->reg1, state->left->reg1, state->right->tree->inst_ls_word);
+       MONO_EMIT_BIALU_IMM (s, tree, OP_SBB_IMM, state->reg2, state->left->reg2, state->right->tree->inst_ms_word);
 }
 
 lreg: OP_LSUB_OVF (lreg, lreg) {
        /* SBB sets the condition code */
-       MONO_EMIT_NEW_BIALU (s, CEE_SUB, state->reg1, state->left->reg1, state->right->reg1);
+       MONO_EMIT_NEW_BIALU (s, OP_SUBCC, state->reg1, state->left->reg1, state->right->reg1);
        MONO_EMIT_NEW_BIALU (s, OP_SBB, state->reg2, state->left->reg2, state->right->reg2);
        MONO_EMIT_NEW_COND_EXC (s, OV, "OverflowException");
 }
 
 lreg: OP_LSUB_OVF_UN (lreg, lreg) {
        /* SBB sets the condition code */
-       MONO_EMIT_NEW_BIALU (s, CEE_SUB, state->reg1, state->left->reg1, state->right->reg1);
+       MONO_EMIT_NEW_BIALU (s, OP_SUBCC, state->reg1, state->left->reg1, state->right->reg1);
        MONO_EMIT_NEW_BIALU (s, OP_SBB, state->reg2, state->left->reg2, state->right->reg2);
        MONO_EMIT_NEW_COND_EXC (s, C, "OverflowException");
 }
@@ -129,8 +319,8 @@ lreg: OP_LAND (lreg, lreg) {
 }
 
 lreg: OP_LAND (lreg, i8con) {  
-       MONO_EMIT_NEW_BIALU_IMM (s, OP_AND_IMM, state->reg1, state->left->reg1, state->right->tree->inst_c0);
-       MONO_EMIT_BIALU_IMM (s, tree, OP_AND_IMM, state->reg2, state->left->reg2, state->right->tree->inst_c1);
+       MONO_EMIT_NEW_BIALU_IMM (s, OP_AND_IMM, state->reg1, state->left->reg1, state->right->tree->inst_ls_word);
+       MONO_EMIT_BIALU_IMM (s, tree, OP_AND_IMM, state->reg2, state->left->reg2, state->right->tree->inst_ms_word);
 }
 
 lreg: OP_LOR (lreg, lreg) {
@@ -139,8 +329,8 @@ lreg: OP_LOR (lreg, lreg) {
 }
 
 lreg: OP_LOR (lreg, i8con) {
-       MONO_EMIT_NEW_BIALU_IMM (s, OP_OR_IMM, state->reg1, state->left->reg1, state->right->tree->inst_c0);
-       MONO_EMIT_BIALU_IMM (s, tree, OP_OR_IMM, state->reg2, state->left->reg2, state->right->tree->inst_c1);
+       MONO_EMIT_NEW_BIALU_IMM (s, OP_OR_IMM, state->reg1, state->left->reg1, state->right->tree->inst_ls_word);
+       MONO_EMIT_BIALU_IMM (s, tree, OP_OR_IMM, state->reg2, state->left->reg2, state->right->tree->inst_ms_word);
 }
 
 lreg: OP_LXOR (lreg, lreg) {
@@ -149,8 +339,8 @@ lreg: OP_LXOR (lreg, lreg) {
 }
 
 lreg: OP_LXOR (lreg, i8con) {
-       MONO_EMIT_NEW_BIALU_IMM (s, OP_XOR_IMM, state->reg1, state->left->reg1, state->right->tree->inst_c0);
-       MONO_EMIT_BIALU_IMM (s, tree, OP_XOR_IMM, state->reg2, state->left->reg2, state->right->tree->inst_c1);
+       MONO_EMIT_NEW_BIALU_IMM (s, OP_XOR_IMM, state->reg1, state->left->reg1, state->right->tree->inst_ls_word);
+       MONO_EMIT_BIALU_IMM (s, tree, OP_XOR_IMM, state->reg2, state->left->reg2, state->right->tree->inst_ms_word);
 }
 
 lreg: OP_LNOT (lreg) {
@@ -161,11 +351,12 @@ lreg: OP_LNOT (lreg) {
 lreg: OP_LNEG (lreg) "4" {
        MONO_EMIT_NEW_UNALU (s, CEE_NOT, state->reg1, state->left->reg1);
        MONO_EMIT_NEW_UNALU (s, CEE_NOT, state->reg2, state->left->reg2);
-       MONO_EMIT_NEW_BIALU_IMM (s, OP_ADD_IMM, state->reg1, state->reg1, 1);
+       /* ADC sets the condition codes */
+       MONO_EMIT_NEW_BIALU_IMM (s, OP_ADC_IMM, state->reg1, state->reg1, 1);
        MONO_EMIT_BIALU_IMM (s, tree, OP_ADC_IMM, state->reg2, state->reg2, 0);
 }
 
-reg: OP_CEQ (OP_COMPARE (lreg, lreg)) {        
+reg: OP_CEQ (OP_LCOMPARE (lreg, lreg)) {       
        MonoInst *word_differs;
        
        MONO_NEW_LABEL (s, word_differs);
@@ -180,7 +371,7 @@ reg: OP_CEQ (OP_COMPARE (lreg, lreg)) {
        mono_bblock_add_inst (s->cbb, word_differs);
 }
 
-reg: OP_CLT (OP_COMPARE (lreg, lreg)) {        
+reg: OP_CLT (OP_LCOMPARE (lreg, lreg)) {       
        MonoInst *set_to_0, *set_to_1;
        
        MONO_NEW_LABEL (s, set_to_0);
@@ -197,7 +388,7 @@ reg: OP_CLT (OP_COMPARE (lreg, lreg)) {
        mono_bblock_add_inst (s->cbb, set_to_0);
 }      
 
-reg: OP_CLT_UN (OP_COMPARE (lreg, lreg)) {     
+reg: OP_CLT_UN (OP_LCOMPARE (lreg, lreg)) {    
        MonoInst *set_to_0, *set_to_1;
        
        MONO_NEW_LABEL (s, set_to_0);
@@ -214,7 +405,7 @@ reg: OP_CLT_UN (OP_COMPARE (lreg, lreg)) {
        mono_bblock_add_inst (s->cbb, set_to_0);
 }      
 
-reg: OP_CGT (OP_COMPARE (lreg, lreg)) {        
+reg: OP_CGT (OP_LCOMPARE (lreg, lreg)) {       
        MonoInst *set_to_0, *set_to_1;
        
        MONO_NEW_LABEL (s, set_to_0);
@@ -231,7 +422,7 @@ reg: OP_CGT (OP_COMPARE (lreg, lreg)) {
        mono_bblock_add_inst (s->cbb, set_to_0);
 }      
 
-reg: OP_CGT_UN (OP_COMPARE (lreg, lreg)) {     
+reg: OP_CGT_UN (OP_LCOMPARE (lreg, lreg)) {    
        MonoInst *set_to_0, *set_to_1;
        
        MONO_NEW_LABEL (s, set_to_0);
@@ -248,21 +439,21 @@ reg: OP_CGT_UN (OP_COMPARE (lreg, lreg)) {
        mono_bblock_add_inst (s->cbb, set_to_0);
 }      
 
-stmt: CEE_BNE_UN (OP_COMPARE (lreg, lreg)) {
+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);
 }
 
-stmt: CEE_BNE_UN (OP_COMPARE (lreg, i8con)) {
-       MONO_EMIT_NEW_BIALU_IMM (s, OP_COMPARE_IMM, -1, state->left->left->reg1, state->left->right->tree->inst_c0);
+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_c1);
+       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);
 }
 
-stmt: CEE_BEQ (OP_COMPARE (lreg, lreg)) {
+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);
@@ -270,15 +461,15 @@ stmt: CEE_BEQ (OP_COMPARE (lreg, lreg)) {
        mono_bblock_add_inst (s->cbb, tree);
 }
 
-stmt: CEE_BEQ (OP_COMPARE (lreg, i8con)) {
+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_c0);
+       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_c1);
+       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);
 }
 
-stmt: CEE_BLE (OP_COMPARE (lreg, lreg)) {
+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);
@@ -287,16 +478,16 @@ stmt: CEE_BLE (OP_COMPARE (lreg, lreg)) {
        MONO_EMIT_NEW_BRANCH_BLOCK (s, CEE_BLE_UN, tree->inst_true_bb);
 }
 
-stmt: CEE_BLE (OP_COMPARE (lreg, i8con)) {
+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_c1);
+       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_c0);
+       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);
 }
 
-stmt: CEE_BLE_UN (OP_COMPARE (lreg, lreg)) {
+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);
@@ -305,16 +496,16 @@ stmt: CEE_BLE_UN (OP_COMPARE (lreg, lreg)) {
        MONO_EMIT_NEW_BRANCH_BLOCK (s, CEE_BLE_UN, tree->inst_true_bb);
 }
 
-stmt: CEE_BLE_UN (OP_COMPARE (lreg, i8con)) {
+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_c1);
+       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_c0);
+       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);
 }
 
-stmt: CEE_BGE (OP_COMPARE (lreg, lreg)) {
+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);
@@ -323,16 +514,16 @@ stmt: CEE_BGE (OP_COMPARE (lreg, lreg)) {
        MONO_EMIT_NEW_BRANCH_BLOCK (s, CEE_BGE_UN, tree->inst_true_bb);
 }
 
-stmt: CEE_BGE (OP_COMPARE (lreg, i8con)) {
+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_c1);
+       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_c0);
+       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);
 }
 
-stmt: CEE_BGE_UN (OP_COMPARE (lreg, lreg)) {
+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);
@@ -341,16 +532,16 @@ stmt: CEE_BGE_UN (OP_COMPARE (lreg, lreg)) {
        MONO_EMIT_NEW_BRANCH_BLOCK (s, CEE_BGE_UN, tree->inst_true_bb);
 }
 
-stmt: CEE_BGE_UN (OP_COMPARE (lreg, i8con)) {
+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_c1);
+       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_c0);
+       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);
 }
 
-stmt: CEE_BLT (OP_COMPARE (lreg, lreg)) {
+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);
@@ -359,16 +550,16 @@ stmt: CEE_BLT (OP_COMPARE (lreg, lreg)) {
        MONO_EMIT_NEW_BRANCH_BLOCK (s, CEE_BLT_UN, tree->inst_true_bb);
 }
 
-stmt: CEE_BLT (OP_COMPARE (lreg, i8con)) {
+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_c1);
+       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_c0);
+       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);
 }
 
-stmt: CEE_BLT_UN (OP_COMPARE (lreg, lreg)) {
+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);
@@ -377,16 +568,16 @@ stmt: CEE_BLT_UN (OP_COMPARE (lreg, lreg)) {
        MONO_EMIT_NEW_BRANCH_BLOCK (s, CEE_BLT_UN, tree->inst_true_bb);
 }
 
-stmt: CEE_BLT_UN (OP_COMPARE (lreg, i8con)) {
+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_c1);
+       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_c0);
+       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);
 }
 
-stmt: CEE_BGT (OP_COMPARE (lreg, lreg)) {
+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);
@@ -395,16 +586,16 @@ stmt: CEE_BGT (OP_COMPARE (lreg, lreg)) {
        MONO_EMIT_NEW_BRANCH_BLOCK (s, CEE_BGT_UN, tree->inst_true_bb);
 }
 
-stmt: CEE_BGT (OP_COMPARE (lreg, i8con)) {
+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_c1);
+       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_c0);
+       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);
 }
 
-stmt: CEE_BGT_UN (OP_COMPARE (lreg, lreg)) {
+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);
@@ -413,12 +604,12 @@ stmt: CEE_BGT_UN (OP_COMPARE (lreg, lreg)) {
        MONO_EMIT_NEW_BRANCH_BLOCK (s, CEE_BGT_UN, tree->inst_true_bb);
 }
 
-stmt: CEE_BGT_UN (OP_COMPARE (lreg, i8con)) {
+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_c1);
+       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_c0);
+       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);
 }
 
@@ -434,32 +625,19 @@ lreg: CEE_CONV_I8 (OP_ICONST) {
 }
 
 lreg: CEE_CONV_I8 (reg) {
-       MonoInst *is_negative, *end_label;
        int tmpreg = mono_regstate_next_int (s->rs);
        
-       MONO_NEW_LABEL (s, is_negative);
-       MONO_NEW_LABEL (s, end_label);
-
        /* branchless code:
         * low = reg;
         * tmp = low > -1 ? 1: 0;
         * high = tmp - 1; if low is zero or pos high becomes 0, else -1
-        * not sure why it doesn't work in practice
         */
        MONO_EMIT_NEW_UNALU (s, OP_MOVE, state->reg1, state->left->reg1);
-       /*MONO_EMIT_NEW_BIALU_IMM (s, OP_COMPARE_IMM, -1, state->reg1, -1);
+       MONO_EMIT_NEW_BIALU_IMM (s, OP_COMPARE_IMM, -1, state->reg1, -1);
        tree->dreg = tmpreg;
        tree->opcode = OP_CGT;
        mono_bblock_add_inst (s->cbb, tree);
-       MONO_EMIT_NEW_BIALU_IMM (s, OP_SUB_IMM, state->reg2, tmpreg, -1);*/
-       MONO_EMIT_NEW_BIALU_IMM (s, OP_COMPARE_IMM, -1, state->reg1, 0);
-       MONO_EMIT_NEW_BRANCH_LABEL (s, CEE_BLT, is_negative);
-       MONO_EMIT_NEW_ICONST (s, tmpreg, 0);
-       MONO_EMIT_NEW_BRANCH_LABEL (s, CEE_BR, end_label);
-       mono_bblock_add_inst (s->cbb, is_negative);
-       MONO_EMIT_NEW_ICONST (s, tmpreg, -1);
-       mono_bblock_add_inst (s->cbb, end_label);
-       MONO_EMIT_NEW_UNALU (s, OP_MOVE, state->reg2, tmpreg);
+       MONO_EMIT_NEW_BIALU_IMM (s, OP_SUB_IMM, state->reg2, tmpreg, 1);
 }
 
 lreg: CEE_CONV_U8 (reg) {
@@ -474,6 +652,23 @@ lreg: CEE_CONV_OVF_U8 (reg) {
        MONO_EMIT_UNALU (s, tree, OP_MOVE, state->reg1, state->left->reg1);
 }
 
+lreg: CEE_CONV_OVF_I8 (reg) {
+       /* a signed 32 bit num always fits in a signed 64 bit one */
+       MONO_EMIT_NEW_BIALU_IMM (s, OP_SHR_IMM, state->reg2, state->left->reg1, 31);
+       MONO_EMIT_UNALU (s, tree, OP_MOVE, state->reg1, state->left->reg1);
+}
+
+lreg: CEE_CONV_OVF_I8_UN (reg) {
+       /* an unsigned 32 bit num always fits in a signed 64 bit one */
+       MONO_EMIT_NEW_ICONST (s, state->reg2, 0);
+       MONO_EMIT_UNALU (s, tree, OP_MOVE, state->reg1, state->left->reg1);
+}
+
+lreg: CEE_CONV_OVF_U8_UN (reg) {
+       MONO_EMIT_NEW_ICONST (s, state->reg2, 0);
+       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);
 }
@@ -487,26 +682,28 @@ lreg: OP_FCONV_TO_U8 (freg) {
 }
 
 reg: OP_LCONV_TO_I4 (i8con) {
-       MONO_EMIT_NEW_ICONST (s, state->reg1, state->left->tree->inst_c0);
+       MONO_EMIT_NEW_ICONST (s, state->reg1, state->left->tree->inst_ls_word);
 }
 
-reg: OP_LCONV_TO_I4 (lreg) {
+reg: OP_LCONV_TO_I4 (lreg),
+reg: OP_LCONV_TO_U4 (lreg) {
        MONO_EMIT_UNALU (s, tree, OP_MOVE, state->reg1, state->left->reg1);
 }
 
-reg: OP_LCONV_TO_U4 (lreg) {
-       MONO_EMIT_UNALU (s, tree, OP_MOVE, state->reg1, state->left->reg1);
+reg: OP_LCONV_TO_I4 (CEE_LDIND_I8 (base)),
+reg: OP_LCONV_TO_U4 (CEE_LDIND_I8 (base)) {
+       MONO_EMIT_LOAD_MEMBASE_OP (s, tree, OP_LOADI4_MEMBASE, state->reg1, 
+                                  state->left->left->tree->inst_basereg, 
+                                  state->left->left->tree->inst_offset + MINI_LS_WORD_OFFSET);
 }
 
-lreg: OP_LCONV_TO_U8 (lreg) {
+lreg: OP_LCONV_TO_U8 (lreg),
+lreg: OP_LCONV_TO_I8 (lreg) {
        MONO_EMIT_NEW_UNALU (s, OP_MOVE, state->reg1, state->left->reg1);
        MONO_EMIT_UNALU (s, tree, OP_MOVE, state->reg2, state->left->reg2);
 }
 
-reg: OP_LCONV_TO_U (lreg) {
-       MONO_EMIT_UNALU (s, tree, OP_MOVE, state->reg1, state->left->reg1);
-}
-
+reg: OP_LCONV_TO_U (lreg),
 reg: OP_LCONV_TO_I (lreg) {
        MONO_EMIT_UNALU (s, tree, OP_MOVE, state->reg1, state->left->reg1);
 }
@@ -527,19 +724,46 @@ reg: OP_LCONV_TO_U2 (lreg) {
        MONO_EMIT_UNALU (s, tree, CEE_CONV_U2, state->reg1, state->left->reg1);
 }
 
+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_UNALU (s, tree, CEE_CONV_I1, state->reg1, state->left->reg1);
+}
+
 reg: OP_LCONV_TO_OVF_I1 (lreg) {
+       MonoInst *is_negative, *end_label;
+
+       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);
+
+       /* Positive */
        MONO_EMIT_NEW_COMPARE_IMM (s, state->left->reg1, 127);
-       MONO_EMIT_NEW_COND_EXC (s, GT, "OverflowException");
+       MONO_EMIT_NEW_COND_EXC (s, GT_UN, "OverflowException");
+       MONO_EMIT_NEW_BRANCH_LABEL (s, CEE_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, "OverflowException");
+       MONO_EMIT_NEW_COND_EXC (s, LT_UN, "OverflowException");
+       mono_bblock_add_inst (s->cbb, end_label);
+
        MONO_EMIT_UNALU (s, tree, CEE_CONV_I1, state->reg1, state->left->reg1);
 }
 
+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");
@@ -551,11 +775,37 @@ reg: OP_LCONV_TO_OVF_U1 (lreg) {
 }
 
 reg: OP_LCONV_TO_OVF_I2 (lreg) {
+       MonoInst *is_negative, *end_label;
+
+       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);
+
+       /* 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);
+
+       /* 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_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");
+
        /* 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");
@@ -564,6 +814,7 @@ reg: OP_LCONV_TO_OVF_I2 (lreg) {
        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");
@@ -600,6 +851,7 @@ reg: OP_LCONV_TO_OVF_I (lreg) {
        mono_bblock_add_inst (s->cbb, tree);
 }
 
+reg: OP_LCONV_TO_OVF_I4_UN (lreg),
 reg: OP_LCONV_TO_OVF_I4 (lreg) {
        tree->dreg = state->reg1;
        tree->sreg1 = state->left->reg1;
@@ -608,4 +860,52 @@ reg: OP_LCONV_TO_OVF_I4 (lreg) {
        mono_bblock_add_inst (s->cbb, tree);
 }
 
+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_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_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_I8 (lreg) {
+       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_UN (lreg) {
+       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_LCALLVIRT (reg) {
+       mini_emit_virtual_call (s, state, tree, OP_LCALL, OP_LCALL_MEMBASE);
+}
+
+lreg: 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 (OP_ICONST) {
+       tree->opcode = OP_LCALL;
+       ((MonoCallInst*)tree)->fptr = state->left->tree->inst_p0;
+       tree->dreg = state->reg1;
+       mono_bblock_add_inst (s->cbb, tree);
+}
+
 %%