* Massimiliano Mantione (massi@ximian.com)
*
* (C) 2006 Novell, Inc. http://www.novell.com
+ * Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
*/
+#include <config.h>
+#ifndef DISABLE_JIT
#include <string.h>
#include <stdio.h>
MonoInst **defs;
gint32 *def_index;
int max;
+ int filter = FILTER_IL_SEQ_POINT;
restart:
/* Manually init the defs entries used by the bblock */
MONO_BB_FOR_EACH_INS (bb, ins) {
+ int sregs [MONO_MAX_SRC_REGS];
+ int num_sregs, i;
+
if ((ins->dreg != -1) && (ins->dreg < max)) {
defs [ins->dreg] = NULL;
#if SIZEOF_REGISTER == 4
defs [ins->dreg + 1] = NULL;
#endif
}
- if ((ins->sreg1 != -1) && (ins->sreg1 < max)) {
- defs [ins->sreg1] = NULL;
-#if SIZEOF_REGISTER == 4
- defs [ins->sreg1 + 1] = NULL;
-#endif
- }
- if ((ins->sreg2 != -1) && (ins->sreg2 < max)) {
- defs [ins->sreg2] = NULL;
+
+ num_sregs = mono_inst_get_src_registers (ins, sregs);
+ for (i = 0; i < num_sregs; ++i) {
+ int sreg = sregs [i];
+ if (sreg < max) {
+ defs [sreg] = NULL;
#if SIZEOF_REGISTER == 4
- defs [ins->sreg2 + 1] = NULL;
+ defs [sreg + 1] = NULL;
#endif
+ }
}
}
MONO_BB_FOR_EACH_INS (bb, ins) {
const char *spec = INS_INFO (ins->opcode);
int regtype, srcindex, sreg;
+ int num_sregs;
+ int sregs [MONO_MAX_SRC_REGS];
if (ins->opcode == OP_NOP) {
MONO_DELETE_INS (bb, ins);
if ((def->opcode == OP_MOVE) && (!defs [def->sreg1] || (def_index [def->sreg1] < def_index [sreg])) && !vreg_is_volatile (cfg, def->sreg1)) {
int vreg = def->sreg1;
- //printf ("CCOPY: R%d -> R%d\n", sreg, vreg);
+ if (cfg->verbose_level > 2) printf ("CCOPY: R%d -> R%d\n", sreg, vreg);
ins->dreg = vreg;
}
}
}
- for (srcindex = 0; srcindex < 2; ++srcindex) {
+ num_sregs = mono_inst_get_src_registers (ins, sregs);
+ for (srcindex = 0; srcindex < num_sregs; ++srcindex) {
MonoInst *def;
+ int nregs;
+
+ nregs = mono_inst_get_src_registers (ins, sregs);
- regtype = srcindex == 0 ? spec [MONO_INST_SRC1] : spec [MONO_INST_SRC2];
- sreg = srcindex == 0 ? ins->sreg1 : ins->sreg2;
+ regtype = spec [MONO_INST_SRC1 + srcindex];
+ sreg = sregs [srcindex];
if ((regtype == ' ') || (sreg == -1) || (!defs [sreg]))
continue;
!vreg_is_volatile (cfg, def->sreg1) &&
/* This avoids propagating local vregs across calls */
((get_vreg_to_inst (cfg, def->sreg1) || !defs [def->sreg1] || (def_index [def->sreg1] >= last_call_index) || (def->opcode == OP_VMOVE))) &&
- !(defs [def->sreg1] && defs [def->sreg1]->next == def) &&
+ !(defs [def->sreg1] && mono_inst_next (defs [def->sreg1], filter) == def) &&
(!MONO_ARCH_USE_FPSTACK || (def->opcode != OP_FMOVE)) &&
(def->opcode != OP_FMOVE)) {
int vreg = def->sreg1;
- //printf ("CCOPY: R%d -> R%d\n", sreg, vreg);
- if (srcindex == 0)
- ins->sreg1 = vreg;
- else
- ins->sreg2 = vreg;
+ if (cfg->verbose_level > 2) printf ("CCOPY/2: R%d -> R%d\n", sreg, vreg);
+ sregs [srcindex] = vreg;
+ mono_inst_set_src_registers (ins, sregs);
/* Allow further iterations */
srcindex = -1;
} else {
ins->inst_imm = def->inst_c0;
}
- if (srcindex == 0)
- ins->sreg1 = -1;
- else
- ins->sreg2 = -1;
+ sregs [srcindex] = -1;
+ mono_inst_set_src_registers (ins, sregs);
if ((opcode2 == OP_VOIDCALL) || (opcode2 == OP_CALL) || (opcode2 == OP_LCALL) || (opcode2 == OP_FCALL))
((MonoCallInst*)ins)->fptr = (gpointer)ins->inst_imm;
}
else {
/* Special cases */
-#if defined(__i386__) || defined(__x86_64__)
+#if defined(TARGET_X86) || defined(TARGET_AMD64)
if ((ins->opcode == OP_X86_LEA) && (srcindex == 1)) {
#if SIZEOF_REGISTER == 8
/* FIXME: Use OP_PADD_IMM when the new JIT is done */
* We have to guarantee that def->sreg1 haven't changed since def->dreg
* was defined. cfg->frame_reg is assumed to remain constant.
*/
- if ((def->sreg1 == cfg->frame_reg) || ((def->next == ins) && (def->dreg != def->sreg1))) {
+ if ((def->sreg1 == cfg->frame_reg) || ((mono_inst_next (def, filter) == ins) && (def->dreg != def->sreg1))) {
ins->inst_basereg = def->sreg1;
ins->inst_offset += def->inst_imm;
}
- } else if ((ins->opcode == OP_ISUB_IMM) && (def->opcode == OP_IADD_IMM) && (def->next == ins)) {
+ } else if ((ins->opcode == OP_ISUB_IMM) && (def->opcode == OP_IADD_IMM) && (mono_inst_next (def, filter) == ins) && (def->dreg != def->sreg1)) {
ins->sreg1 = def->sreg1;
ins->inst_imm -= def->inst_imm;
- } else if ((ins->opcode == OP_IADD_IMM) && (def->opcode == OP_ISUB_IMM) && (def->next == ins)) {
+ } else if ((ins->opcode == OP_IADD_IMM) && (def->opcode == OP_ISUB_IMM) && (mono_inst_next (def, filter) == ins) && (def->dreg != def->sreg1)) {
ins->sreg1 = def->sreg1;
ins->inst_imm -= def->inst_imm;
} else if (ins->opcode == OP_STOREI1_MEMBASE_REG &&
static inline gboolean
reg_is_softreg_no_fpstack (int reg, const char spec)
{
- return (spec == 'i' && reg > MONO_MAX_IREGS)
- || ((spec == 'f' && reg > MONO_MAX_FREGS) && !MONO_ARCH_USE_FPSTACK)
+ return (spec == 'i' && reg >= MONO_MAX_IREGS)
+ || ((spec == 'f' && reg >= MONO_MAX_FREGS) && !MONO_ARCH_USE_FPSTACK)
#ifdef MONO_ARCH_SIMD_INTRINSICS
- || (spec == 'x' && reg > MONO_MAX_XREGS)
+ || (spec == 'x' && reg >= MONO_MAX_XREGS)
#endif
|| (spec == 'v');
}
static inline gboolean
reg_is_softreg (int reg, const char spec)
{
- return (spec == 'i' && reg > MONO_MAX_IREGS)
- || (spec == 'f' && reg > MONO_MAX_FREGS)
+ return (spec == 'i' && reg >= MONO_MAX_IREGS)
+ || (spec == 'f' && reg >= MONO_MAX_FREGS)
#ifdef MONO_ARCH_SIMD_INTRINSICS
- || (spec == 'x' && reg > MONO_MAX_XREGS)
+ || (spec == 'x' && reg >= MONO_MAX_XREGS)
#endif
|| (spec == 'v');
}
+static inline gboolean
+mono_is_simd_accessor (MonoInst *ins)
+{
+ switch (ins->opcode) {
+#ifdef MONO_ARCH_SIMD_INTRINSICS
+ case OP_INSERT_I1:
+ case OP_INSERT_I2:
+ case OP_INSERT_I4:
+ case OP_INSERT_I8:
+ case OP_INSERT_R4:
+ case OP_INSERT_R8:
+
+ case OP_INSERTX_U1_SLOW:
+ case OP_INSERTX_I4_SLOW:
+ case OP_INSERTX_R4_SLOW:
+ case OP_INSERTX_R8_SLOW:
+ case OP_INSERTX_I8_SLOW:
+ return TRUE;
+#endif
+ default:
+ return FALSE;
+ }
+}
+
/**
* mono_local_deadce:
*
/* Manually init the defs entries used by the bblock */
MONO_BB_FOR_EACH_INS (bb, ins) {
const char *spec = INS_INFO (ins->opcode);
+ int sregs [MONO_MAX_SRC_REGS];
+ int num_sregs, i;
if (spec [MONO_INST_DEST] != ' ') {
mono_bitset_clear_fast (used, ins->dreg);
mono_bitset_clear_fast (defined, ins->dreg + 1);
#endif
}
- if (spec [MONO_INST_SRC1] != ' ') {
- mono_bitset_clear_fast (used, ins->sreg1);
+ num_sregs = mono_inst_get_src_registers (ins, sregs);
+ for (i = 0; i < num_sregs; ++i) {
+ mono_bitset_clear_fast (used, sregs [i]);
#if SIZEOF_REGISTER == 4
- mono_bitset_clear_fast (used, ins->sreg1 + 1);
-#endif
- }
- if (spec [MONO_INST_SRC2] != ' ') {
- mono_bitset_clear_fast (used, ins->sreg2);
-#if SIZEOF_REGISTER == 4
- mono_bitset_clear_fast (used, ins->sreg2 + 1);
+ mono_bitset_clear_fast (used, sregs [i] + 1);
#endif
}
}
*/
MONO_BB_FOR_EACH_INS_REVERSE_SAFE (bb, prev, ins) {
const char *spec = INS_INFO (ins->opcode);
+ int sregs [MONO_MAX_SRC_REGS];
+ int num_sregs, i;
+ MonoInst *prev_f = mono_inst_prev (ins, FILTER_NOP | FILTER_IL_SEQ_POINT);
if (ins->opcode == OP_NOP) {
MONO_DELETE_INS (bb, ins);
g_assert (ins->opcode > MONO_CEE_LAST);
- if (MONO_IS_NON_FP_MOVE (ins) && ins->prev) {
+ if (MONO_IS_NON_FP_MOVE (ins) && prev_f) {
MonoInst *def;
const char *spec2;
- def = ins->prev;
- while (def->prev && (def->opcode == OP_NOP))
- def = def->prev;
+ def = prev_f;
spec2 = INS_INFO (def->opcode);
/*
* This isn't copyprop, not deadce, but it can only be performed
* after handle_global_vregs () has run.
*/
- if (!get_vreg_to_inst (cfg, ins->sreg1) && (spec2 [MONO_INST_DEST] != ' ') && (def->dreg == ins->sreg1) && !mono_bitset_test_fast (used, ins->sreg1) && !MONO_IS_STORE_MEMBASE (def) && reg_is_softreg (ins->sreg1, spec [MONO_INST_DEST])) {
+ if (!get_vreg_to_inst (cfg, ins->sreg1) && (spec2 [MONO_INST_DEST] != ' ') && (def->dreg == ins->sreg1) && !mono_bitset_test_fast (used, ins->sreg1) && !MONO_IS_STORE_MEMBASE (def) && reg_is_softreg (ins->sreg1, spec [MONO_INST_DEST]) && !mono_is_simd_accessor (def)) {
if (cfg->verbose_level > 2) {
printf ("\tReverse copyprop in BB%d on ", bb->block_num);
mono_print_ins (ins);
(!get_vreg_to_inst (cfg, ins->dreg) || (!bb->extended && !vreg_is_volatile (cfg, ins->dreg) && mono_bitset_test_fast (defined, ins->dreg))) &&
MONO_INS_HAS_NO_SIDE_EFFECT (ins)) {
/* Happens with CMOV instructions */
- if (ins->prev && ins->prev->opcode == OP_ICOMPARE_IMM) {
- MonoInst *prev = ins->prev;
+ if (prev_f && prev_f->opcode == OP_ICOMPARE_IMM) {
+ MonoInst *prev = prev_f;
/*
* Can't use DELETE_INS since that would interfere with the
* FOR_EACH_INS loop.
if (spec [MONO_INST_DEST] != ' ')
mono_bitset_set_fast (defined, ins->dreg);
- if (spec [MONO_INST_SRC1] != ' ')
- mono_bitset_set_fast (used, ins->sreg1);
- if (spec [MONO_INST_SRC2] != ' ')
- mono_bitset_set_fast (used, ins->sreg2);
+ num_sregs = mono_inst_get_src_registers (ins, sregs);
+ for (i = 0; i < num_sregs; ++i)
+ mono_bitset_set_fast (used, sregs [i]);
if (MONO_IS_STORE_MEMBASE (ins))
mono_bitset_set_fast (used, ins->dreg);
//mono_print_code (cfg, "AFTER LOCAL-DEADCE");
}
+
+#endif /* DISABLE_JIT */