* 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>
return mono_bitset_mem_new (mem, max_size, MONO_BITSET_DONT_FREE);
}
+/*
+ * Replaces ins with optimized opcodes.
+ * Returns TRUE if additional vregs were allocated.
+ */
+static gboolean
+mono_strength_reduction_ins (MonoCompile *cfg, MonoBasicBlock *bb, MonoInst *ins, const char **spec)
+{
+ gboolean allocated_vregs = FALSE;
+
+ /* FIXME: Add long/float */
+ switch (ins->opcode) {
+ case OP_MOVE:
+ case OP_XMOVE:
+ if (ins->dreg == ins->sreg1) {
+ MONO_DELETE_INS (bb, ins);
+ }
+ break;
+ case OP_ADD_IMM:
+ case OP_IADD_IMM:
+ case OP_SUB_IMM:
+ case OP_ISUB_IMM:
+#if SIZEOF_REGISTER == 8
+ case OP_LADD_IMM:
+ case OP_LSUB_IMM:
+#endif
+ if (ins->inst_imm == 0) {
+ ins->opcode = OP_MOVE;
+ }
+ break;
+ case OP_MUL_IMM:
+ case OP_IMUL_IMM:
+#if SIZEOF_REGISTER == 8
+ case OP_LMUL_IMM:
+#endif
+ if (ins->inst_imm == 0) {
+ ins->opcode = (ins->opcode == OP_LMUL_IMM) ? OP_I8CONST : OP_ICONST;
+ ins->inst_c0 = 0;
+ ins->sreg1 = -1;
+ } else if (ins->inst_imm == 1) {
+ ins->opcode = OP_MOVE;
+ } else if ((ins->opcode == OP_IMUL_IMM) && (ins->inst_imm == -1)) {
+ ins->opcode = OP_INEG;
+ } else if ((ins->opcode == OP_LMUL_IMM) && (ins->inst_imm == -1)) {
+ ins->opcode = OP_LNEG;
+ } else {
+ int power2 = mono_is_power_of_two (ins->inst_imm);
+ if (power2 >= 0) {
+ ins->opcode = (ins->opcode == OP_MUL_IMM) ? OP_SHL_IMM : ((ins->opcode == OP_LMUL_IMM) ? OP_LSHL_IMM : OP_ISHL_IMM);
+ ins->inst_imm = power2;
+ }
+ }
+ break;
+ case OP_IREM_UN_IMM:
+ case OP_IDIV_UN_IMM: {
+ int c = ins->inst_imm;
+ int power2 = mono_is_power_of_two (c);
+
+ if (power2 >= 0) {
+ if (ins->opcode == OP_IREM_UN_IMM) {
+ ins->opcode = OP_IAND_IMM;
+ ins->sreg2 = -1;
+ ins->inst_imm = (1 << power2) - 1;
+ } else if (ins->opcode == OP_IDIV_UN_IMM) {
+ ins->opcode = OP_ISHR_UN_IMM;
+ ins->sreg2 = -1;
+ ins->inst_imm = power2;
+ }
+ }
+ break;
+ }
+ case OP_IDIV_IMM: {
+ int c = ins->inst_imm;
+ int power2 = mono_is_power_of_two (c);
+ MonoInst *tmp1, *tmp2, *tmp3, *tmp4;
+
+ /* FIXME: Move this elsewhere cause its hard to implement it here */
+ if (power2 == 1) {
+ int r1 = mono_alloc_ireg (cfg);
+
+ NEW_BIALU_IMM (cfg, tmp1, OP_ISHR_UN_IMM, r1, ins->sreg1, 31);
+ mono_bblock_insert_after_ins (bb, ins, tmp1);
+ NEW_BIALU (cfg, tmp2, OP_IADD, r1, r1, ins->sreg1);
+ mono_bblock_insert_after_ins (bb, tmp1, tmp2);
+ NEW_BIALU_IMM (cfg, tmp3, OP_ISHR_IMM, ins->dreg, r1, 1);
+ mono_bblock_insert_after_ins (bb, tmp2, tmp3);
+
+ NULLIFY_INS (ins);
+ allocated_vregs = TRUE;
+ } else if (power2 > 0 && power2 < 31) {
+ int r1 = mono_alloc_ireg (cfg);
+
+ NEW_BIALU_IMM (cfg, tmp1, OP_ISHR_IMM, r1, ins->sreg1, 31);
+ mono_bblock_insert_after_ins (bb, ins, tmp1);
+ NEW_BIALU_IMM (cfg, tmp2, OP_ISHR_UN_IMM, r1, r1, (32 - power2));
+ mono_bblock_insert_after_ins (bb, tmp1, tmp2);
+ NEW_BIALU (cfg, tmp3, OP_IADD, r1, r1, ins->sreg1);
+ mono_bblock_insert_after_ins (bb, tmp2, tmp3);
+ NEW_BIALU_IMM (cfg, tmp4, OP_ISHR_IMM, ins->dreg, r1, power2);
+ mono_bblock_insert_after_ins (bb, tmp3, tmp4);
+
+ NULLIFY_INS (ins);
+ allocated_vregs = TRUE;
+ }
+ break;
+ }
+ default:
+ break;
+ }
+
+ *spec = INS_INFO (ins->opcode);
+ return allocated_vregs;
+}
+
/*
* mono_local_cprop:
*
MonoInst **defs;
gint32 *def_index;
int max;
+ int filter = FILTER_IL_SEQ_POINT;
restart:
max = cfg->next_vreg;
- defs = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*) * (cfg->next_vreg + 1));
- def_index = mono_mempool_alloc (cfg->mempool, sizeof (guint32) * (cfg->next_vreg + 1));
+ defs = (MonoInst **)mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*) * cfg->next_vreg);
+ def_index = (gint32 *)mono_mempool_alloc (cfg->mempool, sizeof (guint32) * cfg->next_vreg);
for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
MonoInst *ins;
/* FIXME: Optimize this */
if (ins->opcode == OP_LDADDR) {
- MonoInst *var = ins->inst_p0;
+ MonoInst *var = (MonoInst *)ins->inst_p0;
defs [var->dreg] = NULL;
/*
num_sregs = mono_inst_get_src_registers (ins, sregs);
for (srcindex = 0; srcindex < num_sregs; ++srcindex) {
MonoInst *def;
- int nsregs;
- nsregs = mono_inst_get_src_registers (ins, sregs);
+ mono_inst_get_src_registers (ins, sregs);
regtype = spec [MONO_INST_SRC1 + srcindex];
sreg = sregs [srcindex];
!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;
* 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) && (def->dreg != def->sreg1)) {
+ } 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) && (def->dreg != def->sreg1)) {
+ } 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 &&
}
/* Do strength reduction here */
- /* FIXME: Add long/float */
- switch (ins->opcode) {
- case OP_MOVE:
- case OP_XMOVE:
- if (ins->dreg == ins->sreg1) {
- MONO_DELETE_INS (bb, ins);
- spec = INS_INFO (ins->opcode);
- }
- break;
- case OP_ADD_IMM:
- case OP_IADD_IMM:
- case OP_SUB_IMM:
- case OP_ISUB_IMM:
-#if SIZEOF_REGISTER == 8
- case OP_LADD_IMM:
- case OP_LSUB_IMM:
-#endif
- if (ins->inst_imm == 0) {
- ins->opcode = OP_MOVE;
- spec = INS_INFO (ins->opcode);
- }
- break;
- case OP_MUL_IMM:
- case OP_IMUL_IMM:
-#if SIZEOF_REGISTER == 8
- case OP_LMUL_IMM:
-#endif
- if (ins->inst_imm == 0) {
- ins->opcode = (ins->opcode == OP_LMUL_IMM) ? OP_I8CONST : OP_ICONST;
- ins->inst_c0 = 0;
- ins->sreg1 = -1;
- } else if (ins->inst_imm == 1) {
- ins->opcode = OP_MOVE;
- } else if ((ins->opcode == OP_IMUL_IMM) && (ins->inst_imm == -1)) {
- ins->opcode = OP_INEG;
- } else if ((ins->opcode == OP_LMUL_IMM) && (ins->inst_imm == -1)) {
- ins->opcode = OP_LNEG;
- } else {
- int power2 = mono_is_power_of_two (ins->inst_imm);
- if (power2 >= 0) {
- ins->opcode = (ins->opcode == OP_MUL_IMM) ? OP_SHL_IMM : ((ins->opcode == OP_LMUL_IMM) ? OP_LSHL_IMM : OP_ISHL_IMM);
- ins->inst_imm = power2;
- }
- }
- spec = INS_INFO (ins->opcode);
- break;
- case OP_IREM_UN_IMM:
- case OP_IDIV_UN_IMM: {
- int c = ins->inst_imm;
- int power2 = mono_is_power_of_two (c);
-
- if (power2 >= 0) {
- if (ins->opcode == OP_IREM_UN_IMM) {
- ins->opcode = OP_IAND_IMM;
- ins->sreg2 = -1;
- ins->inst_imm = (1 << power2) - 1;
- } else if (ins->opcode == OP_IDIV_UN_IMM) {
- ins->opcode = OP_ISHR_UN_IMM;
- ins->sreg2 = -1;
- ins->inst_imm = power2;
- }
- }
- spec = INS_INFO (ins->opcode);
- break;
- }
- case OP_IDIV_IMM: {
- int c = ins->inst_imm;
- int power2 = mono_is_power_of_two (c);
- MonoInst *tmp1, *tmp2, *tmp3, *tmp4;
-
- /* FIXME: Move this elsewhere cause its hard to implement it here */
- if (power2 == 1) {
- int r1 = mono_alloc_ireg (cfg);
-
- NEW_BIALU_IMM (cfg, tmp1, OP_ISHR_UN_IMM, r1, ins->sreg1, 31);
- mono_bblock_insert_after_ins (bb, ins, tmp1);
- NEW_BIALU (cfg, tmp2, OP_IADD, r1, r1, ins->sreg1);
- mono_bblock_insert_after_ins (bb, tmp1, tmp2);
- NEW_BIALU_IMM (cfg, tmp3, OP_ISHR_IMM, ins->dreg, r1, 1);
- mono_bblock_insert_after_ins (bb, tmp2, tmp3);
-
- NULLIFY_INS (ins);
-
- // We allocated a new vreg, so need to restart
- goto restart;
- } else if (power2 > 0) {
- int r1 = mono_alloc_ireg (cfg);
-
- NEW_BIALU_IMM (cfg, tmp1, OP_ISHR_IMM, r1, ins->sreg1, 31);
- mono_bblock_insert_after_ins (bb, ins, tmp1);
- NEW_BIALU_IMM (cfg, tmp2, OP_ISHR_UN_IMM, r1, r1, (32 - power2));
- mono_bblock_insert_after_ins (bb, tmp1, tmp2);
- NEW_BIALU (cfg, tmp3, OP_IADD, r1, r1, ins->sreg1);
- mono_bblock_insert_after_ins (bb, tmp2, tmp3);
- NEW_BIALU_IMM (cfg, tmp4, OP_ISHR_IMM, ins->dreg, r1, power2);
- mono_bblock_insert_after_ins (bb, tmp3, tmp4);
-
- NULLIFY_INS (ins);
-
- // We allocated a new vreg, so need to restart
- goto restart;
- }
- break;
- }
- }
-
+ if (mono_strength_reduction_ins (cfg, bb, ins, &spec))
+ goto restart;
+
if (spec [MONO_INST_DEST] != ' ') {
MonoInst *def = defs [ins->dreg];
|| (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:
*
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.
//mono_print_code (cfg, "AFTER LOCAL-DEADCE");
}
+
+#endif /* DISABLE_JIT */