*
* (C) 2002 Ximian, Inc.
* Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#include "mini.h"
case OP_FCONV_TO_OVF_U8_UN:
case OP_FCONV_TO_OVF_I_UN:
case OP_FCONV_TO_OVF_U_UN:
- cfg->exception_type = MONO_EXCEPTION_INVALID_PROGRAM;
- cfg->exception_message = g_strdup_printf ("float conv.ovf.un opcodes not supported.");
+ mono_cfg_set_exception_invalid_program (cfg, g_strdup_printf ("float conv.ovf.un opcodes not supported."));
break;
case OP_IDIV:
}
break;
-#if SIZEOF_REGISTER == 8
- case OP_LREM_IMM:
-#endif
- case OP_IREM_IMM: {
- int power = mono_is_power_of_two (ins->inst_imm);
- if (ins->inst_imm == 1) {
- ins->opcode = OP_ICONST;
- MONO_INST_NULLIFY_SREGS (ins);
- ins->inst_c0 = 0;
-#if __s390__
+#if SIZEOF_VOID_P == 8
+ case OP_LDIV:
+ case OP_LREM:
+ case OP_LDIV_UN:
+ case OP_LREM_UN:
+ if (cfg->backend->emulate_div && mono_arch_opcode_needs_emulation (cfg, ins->opcode))
+ emulate = TRUE;
+ if (!emulate) {
+ if (cfg->backend->need_div_check) {
+ int reg1 = alloc_ireg (cfg);
+ int reg2 = alloc_ireg (cfg);
+ int reg3 = alloc_ireg (cfg);
+ /* b == 0 */
+ MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg2, 0);
+ MONO_EMIT_NEW_COND_EXC (cfg, IEQ, "DivideByZeroException");
+ if (ins->opcode == OP_LDIV || ins->opcode == OP_LREM) {
+ /* b == -1 && a == 0x80000000 */
+ MONO_EMIT_NEW_I8CONST (cfg, reg3, -1);
+ MONO_EMIT_NEW_BIALU (cfg, OP_LCOMPARE, -1, ins->sreg2, reg3);
+ MONO_EMIT_NEW_UNALU (cfg, OP_LCEQ, reg1, -1);
+ MONO_EMIT_NEW_I8CONST (cfg, reg3, 0x8000000000000000L);
+ MONO_EMIT_NEW_BIALU (cfg, OP_LCOMPARE, -1, ins->sreg1, reg3);
+ MONO_EMIT_NEW_UNALU (cfg, OP_LCEQ, reg2, -1);
+ MONO_EMIT_NEW_BIALU (cfg, OP_IAND, reg1, reg1, reg2);
+ MONO_EMIT_NEW_ICOMPARE_IMM (cfg, reg1, 1);
+ MONO_EMIT_NEW_COND_EXC (cfg, IEQ, "OverflowException");
+ }
+ }
+ MONO_EMIT_NEW_BIALU (cfg, ins->opcode, ins->dreg, ins->sreg1, ins->sreg2);
+ NULLIFY_INS (ins);
}
-#else
- } else if ((ins->inst_imm > 0) && (ins->inst_imm < (1LL << 32)) && (power != -1)) {
- gboolean is_long = ins->opcode == OP_LREM_IMM;
- int compensator_reg = alloc_ireg (cfg);
- int intermediate_reg;
-
- /* Based on gcc code */
-
- /* Add compensation for negative numerators */
+ break;
+#endif
- if (power > 1) {
- intermediate_reg = compensator_reg;
- MONO_EMIT_NEW_BIALU_IMM (cfg, is_long ? OP_LSHR_IMM : OP_ISHR_IMM, intermediate_reg, ins->sreg1, is_long ? 63 : 31);
- } else {
- intermediate_reg = ins->sreg1;
+ case OP_DIV_IMM:
+ case OP_REM_IMM:
+ case OP_IDIV_IMM:
+ case OP_IREM_IMM:
+ case OP_IDIV_UN_IMM:
+ case OP_IREM_UN_IMM:
+ if (cfg->backend->need_div_check) {
+ int reg1 = alloc_ireg (cfg);
+ /* b == 0 */
+ if (ins->inst_imm == 0) {
+ // FIXME: Optimize this
+ MONO_EMIT_NEW_ICONST (cfg, reg1, 0);
+ MONO_EMIT_NEW_ICOMPARE_IMM (cfg, reg1, 0);
+ MONO_EMIT_NEW_COND_EXC (cfg, IEQ, "DivideByZeroException");
}
-
- MONO_EMIT_NEW_BIALU_IMM (cfg, is_long ? OP_LSHR_UN_IMM : OP_ISHR_UN_IMM, compensator_reg, intermediate_reg, (is_long ? 64 : 32) - power);
- MONO_EMIT_NEW_BIALU (cfg, is_long ? OP_LADD : OP_IADD, ins->dreg, ins->sreg1, compensator_reg);
- /* Compute remainder */
- MONO_EMIT_NEW_BIALU_IMM (cfg, is_long ? OP_LAND_IMM : OP_AND_IMM, ins->dreg, ins->dreg, (1 << power) - 1);
- /* Remove compensation */
- MONO_EMIT_NEW_BIALU (cfg, is_long ? OP_LSUB : OP_ISUB, ins->dreg, ins->dreg, compensator_reg);
-
+ if ((ins->opcode == OP_DIV_IMM || ins->opcode == OP_IDIV_IMM || ins->opcode == OP_REM_IMM || ins->opcode == OP_IREM_IMM) &&
+ (ins->inst_imm == -1)) {
+ /* b == -1 && a == 0x80000000 */
+ MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 0x80000000);
+ MONO_EMIT_NEW_COND_EXC (cfg, IEQ, "OverflowException");
+ }
+ MONO_EMIT_NEW_BIALU_IMM (cfg, ins->opcode, ins->dreg, ins->sreg1, ins->inst_imm);
NULLIFY_INS (ins);
+ } else {
+ emulate = TRUE;
}
-#endif
break;
- }
default:
emulate = TRUE;
MONO_EMIT_NEW_BIALU_IMM (cfg, OP_XOR_IMM, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), tree->inst_ls_word);
MONO_EMIT_NEW_BIALU_IMM (cfg, OP_XOR_IMM, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), tree->inst_ms_word);
break;
+#ifdef TARGET_POWERPC
+/* FIXME This is normally handled in cprop. Proper fix or remove if no longer needed. */
case OP_LSHR_UN_IMM:
if (tree->inst_c1 == 32) {
* later apply the speedup to the left shift as well
* See BUG# 57957.
*/
- /* FIXME: Move this to the strength reduction pass */
/* just move the upper half to the lower and zero the high word */
MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_LS (tree->dreg), MONO_LVREG_MS (tree->sreg1));
MONO_EMIT_NEW_ICONST (cfg, MONO_LVREG_MS (tree->dreg), 0);
}
break;
- case OP_LSHL_IMM:
- if (tree->inst_c1 == 32) {
- /* just move the lower half to the upper and zero the lower word */
- MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_MS (tree->dreg), MONO_LVREG_LS (tree->sreg1));
- MONO_EMIT_NEW_ICONST (cfg, MONO_LVREG_LS (tree->dreg), 0);
- }
- break;
-
+#endif
case OP_LCOMPARE: {
MonoInst *next = mono_inst_next (tree, FILTER_IL_SEQ_POINT);
case OP_STOREV_MEMBASE: {
src_var = get_vreg_to_inst (cfg, ins->sreg1);
+ if (COMPILE_LLVM (cfg) && !mini_is_gsharedvt_klass (ins->klass) && !cfg->gen_write_barriers)
+ break;
+
if (!src_var) {
g_assert (ins->klass);
src_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->sreg1);
MONO_INST_NEW (cfg, iargs [2], OP_MOVE);
iargs [2]->dreg = ins->sreg1;
- dest = mono_emit_jit_icall (cfg, mono_array_new, iargs);
+ dest = mono_emit_jit_icall (cfg, ves_icall_array_new, iargs);
dest->dreg = ins->dreg;
} else {
MonoClass *array_class = mono_array_class_get (ins->inst_newa_class, 1);
if (managed_alloc)
dest = mono_emit_method_call (cfg, managed_alloc, iargs, NULL);
else
- dest = mono_emit_jit_icall (cfg, mono_array_new_specific, iargs);
+ dest = mono_emit_jit_icall (cfg, ves_icall_array_new_specific, iargs);
dest->dreg = ins->dreg;
}
break;
/* We emit the call on a separate dummy basic block */
cfg->cbb = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
- first_bb = cfg->cbb;
+ first_bb = cfg->cbb;
- call = mono_emit_jit_icall_by_info (cfg, info, args);
+ call = mono_emit_jit_icall_by_info (cfg, bb->real_offset, info, args);
call->dreg = ins->dreg;
/* Replace ins with the emitted code and do the necessary bb linking */