Author: zoltan
Date: 2006-06-21 16:58:40 -0400 (Wed, 21 Jun 2006)
New Revision: 61918
Modified:
branches/vargaz/mini-linear-il/mono/mono/mini/ChangeLog
branches/vargaz/mini-linear-il/mono/mono/mini/basic.cs
branches/vargaz/mini-linear-il/mono/mono/mini/cpu-pentium.md
branches/vargaz/mini-linear-il/mono/mono/mini/method-to-ir.c
branches/vargaz/mini-linear-il/mono/mono/mini/mini-codegen.c
branches/vargaz/mini-linear-il/mono/mono/mini/mini-x86.c
Log:
2006-06-21 Zoltan Varga <[EMAIL PROTECTED]>
* method-to-ir.c (mono_op_to_op_imm): Enable div/rem -> div_imm/rem_imm
conversion.
* mini-x86.c cpu-pentium.md: Finish support for div/rem imm.
* mini-codegen.c (mono_local_regalloc): When emitting a copy to put
sreg1 in the
proper fixed reg, update ins->sreg1 as well.
* basic.cs: Add tests.
Modified: branches/vargaz/mini-linear-il/mono/mono/mini/ChangeLog
===================================================================
--- branches/vargaz/mini-linear-il/mono/mono/mini/ChangeLog 2006-06-21
20:45:36 UTC (rev 61917)
+++ branches/vargaz/mini-linear-il/mono/mono/mini/ChangeLog 2006-06-21
20:58:40 UTC (rev 61918)
@@ -1,3 +1,14 @@
+2006-06-21 Zoltan Varga <[EMAIL PROTECTED]>
+
+ * method-to-ir.c (mono_op_to_op_imm): Enable div/rem -> div_imm/rem_imm
conversion.
+
+ * mini-x86.c cpu-pentium.md: Finish support for div/rem imm.
+
+ * mini-codegen.c (mono_local_regalloc): When emitting a copy to put
sreg1 in the
+ proper fixed reg, update ins->sreg1 as well.
+
+ * basic.cs: Add tests.
+
2006-06-19 Zoltan Varga <[EMAIL PROTECTED]>
* local-propagation.c (mono_local_deadce): Fix a typo in reverse
copyprop.
Modified: branches/vargaz/mini-linear-il/mono/mono/mini/basic.cs
===================================================================
--- branches/vargaz/mini-linear-il/mono/mono/mini/basic.cs 2006-06-21
20:45:36 UTC (rev 61917)
+++ branches/vargaz/mini-linear-il/mono/mono/mini/basic.cs 2006-06-21
20:58:40 UTC (rev 61918)
@@ -1145,4 +1145,69 @@
return (int)(i % j);
}
+
+ public static int test_0_div_opt () {
+ int i;
+
+ // Avoid cfolding this
+ i = 0;
+ for (int j = 0; j < 1234567; ++j)
+ i ++;
+ if ((i / 2) != 617283)
+ return 1;
+ if ((i / 4) != 308641)
+ return 2;
+ if ((i / 8) != 154320)
+ return 3;
+ if ((i / 16) != 77160)
+ return 4;
+
+ // Avoid cfolding this
+ i = 0;
+ for (int j = 0; j < 1234567; ++j)
+ i --;
+ if ((i / 2) != -617283)
+ return 5;
+ if ((i / 4) != -308641)
+ return 6;
+ if ((i / 8) != -154320)
+ return 7;
+ if ((i / 16) != -77160)
+ return 8;
+
+ return 0;
+ }
+
+ public static int test_0_rem_opt () {
+ int i;
+
+ // Avoid cfolding this
+ i = 0;
+ for (int j = 0; j < 29; ++j)
+ i ++;
+ if ((i % 2) != 1)
+ return 1;
+ if ((i % 4) != 1)
+ return 2;
+ if ((i % 8) != 5)
+ return 3;
+ if ((i % 16) != 13)
+ return 4;
+
+ // Avoid cfolding this
+ i = 0;
+ for (int j = 0; j < 29; ++j)
+ i --;
+ if ((i % 2) != -1)
+ return 5;
+ if ((i % 4) != -1)
+ return 6;
+ if ((i % 8) != -5)
+ return 7;
+ if ((i % 16) != -13)
+ return 8;
+
+ return 0;
+ }
+
}
Modified: branches/vargaz/mini-linear-il/mono/mono/mini/cpu-pentium.md
===================================================================
--- branches/vargaz/mini-linear-il/mono/mono/mini/cpu-pentium.md
2006-06-21 20:45:36 UTC (rev 61917)
+++ branches/vargaz/mini-linear-il/mono/mono/mini/cpu-pentium.md
2006-06-21 20:58:40 UTC (rev 61918)
@@ -267,12 +267,11 @@
subcc_imm: dest:i src1:i len:6 clob:1
sub_imm: dest:i src1:i len:6 clob:1
mul_imm: dest:i src1:i len:9
-# there is no actual support for division or reminder by immediate
-# we simulate them, though (but we need to change the burg rules
-# to allocate a symbolic reg for src2)
+
div_imm: dest:a src1:a src2:i len:15 clob:d
div_un_imm: dest:a src1:a src2:i len:15 clob:d
-rem_imm: dest:d src1:a src2:i len:15 clob:a
+# This returns EAX
+rem_imm: dest:a src1:a src2:i len:15 clob:d
rem_un_imm: dest:d src1:a src2:i len:15 clob:a
and_imm: dest:i src1:i len:6 clob:1
or_imm: dest:i src1:i len:6 clob:1
@@ -291,7 +290,8 @@
# to allocate a symbolic reg for src2)
int_div_imm: dest:a src1:a len:15 clob:d
int_div_un_imm: dest:a src1:a len:15 clob:d
-int_rem_imm: dest:d src1:a len:15 clob:a
+# This returns EAX
+int_rem_imm: dest:a src1:a len:15 clob:d
int_rem_un_imm: dest:d src1:a len:15 clob:a
int_and_imm: dest:i src1:i len:6 clob:1
int_or_imm: dest:i src1:i len:6 clob:1
Modified: branches/vargaz/mini-linear-il/mono/mono/mini/method-to-ir.c
===================================================================
--- branches/vargaz/mini-linear-il/mono/mono/mini/method-to-ir.c
2006-06-21 20:45:36 UTC (rev 61917)
+++ branches/vargaz/mini-linear-il/mono/mono/mini/method-to-ir.c
2006-06-21 20:58:40 UTC (rev 61918)
@@ -8857,7 +8857,6 @@
return OP_IADD_IMM;
case OP_ISUB:
return OP_ISUB_IMM;
- /* FIXME: See the FIXMEs in mini-x86.c
case OP_IDIV:
return OP_IDIV_IMM;
case OP_IDIV_UN:
@@ -8866,7 +8865,6 @@
return OP_IREM_IMM;
case OP_IREM_UN:
return OP_IREM_UN_IMM;
- */
case OP_IMUL:
return OP_IMUL_IMM;
case OP_IAND:
Modified: branches/vargaz/mini-linear-il/mono/mono/mini/mini-codegen.c
===================================================================
--- branches/vargaz/mini-linear-il/mono/mono/mini/mini-codegen.c
2006-06-21 20:45:36 UTC (rev 61917)
+++ branches/vargaz/mini-linear-il/mono/mono/mini/mini-codegen.c
2006-06-21 20:58:40 UTC (rev 61918)
@@ -1702,6 +1702,7 @@
MonoInst *copy = create_copy_ins (cfg,
dest_sreg1, val, NULL, ip, fp);
insert_before_ins (ins, tmp, copy);
sreg2_mask &= ~(regmask (dest_sreg1));
+ val = dest_sreg1;
}
ins->sreg1 = val;
Modified: branches/vargaz/mini-linear-il/mono/mono/mini/mini-x86.c
===================================================================
--- branches/vargaz/mini-linear-il/mono/mono/mini/mini-x86.c 2006-06-21
20:45:36 UTC (rev 61917)
+++ branches/vargaz/mini-linear-il/mono/mono/mini/mini-x86.c 2006-06-21
20:58:40 UTC (rev 61918)
@@ -1535,14 +1535,9 @@
static void
peephole_pass_1 (MonoCompile *cfg, MonoBasicBlock *bb)
{
- MonoInst *ins, *temp, *last_ins = NULL;
+ MonoInst *ins, *last_ins = NULL;
ins = bb->code;
- if (bb->max_ireg > cfg->rs->next_vireg)
- cfg->rs->next_vireg = bb->max_ireg;
- if (bb->max_freg > cfg->rs->next_vfreg)
- cfg->rs->next_vfreg = bb->max_freg;
-
while (ins) {
switch (ins->opcode) {
case OP_IADD_IMM:
@@ -1566,37 +1561,6 @@
} else if ((ins->inst_imm == 1) && (ins->dreg ==
ins->sreg1))
ins->opcode = OP_X86_DEC_REG;
break;
- case OP_IDIV_IMM:
- case OP_IREM_IMM:
- case OP_IDIV_UN_IMM:
- case OP_IREM_UN_IMM:
- /*
- * Keep the cases where we could generated optimized
code, otherwise convert
- * to the non-imm variant.
- * FIXME: Do this always, not just when peephole is
enabled
- */
- if (mono_is_power_of_two (ins->inst_imm) < 0) {
- NEW_INS (cfg, temp, OP_ICONST);
- temp->inst_c0 = ins->inst_imm;
- temp->dreg = mono_regstate_next_int (cfg->rs);
- switch (ins->opcode) {
- case OP_IDIV_IMM:
- ins->opcode = OP_IDIV;
- break;
- case OP_IREM_IMM:
- ins->opcode = OP_IREM;
- break;
- case OP_IDIV_UN_IMM:
- ins->opcode = OP_IDIV_UN;
- break;
- case OP_IREM_UN_IMM:
- ins->opcode = OP_IREM_UN;
- break;
- }
- ins->sreg2 = temp->dreg;
- break;
- }
- break;
case OP_COMPARE_IMM:
case OP_ICOMPARE_IMM:
/* OP_COMPARE_IMM (reg, 0)
@@ -1776,9 +1740,6 @@
ins = ins->next;
}
bb->last_ins = last_ins;
-
- bb->max_ireg = cfg->rs->next_vireg;
- bb->max_freg = cfg->rs->next_vfreg;
}
static void
@@ -2002,6 +1963,72 @@
bb->last_ins = last_ins;
}
+/*
+ * mono_arch_lowering_pass:
+ *
+ * Converts complex opcodes into simpler ones so that each IR instruction
+ * corresponds to one machine instruction.
+ */
+static void
+mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb)
+{
+ MonoInst *ins, *temp, *last_ins = NULL;
+ ins = bb->code;
+
+ if (bb->max_ireg > cfg->rs->next_vireg)
+ cfg->rs->next_vireg = bb->max_ireg;
+ if (bb->max_freg > cfg->rs->next_vfreg)
+ cfg->rs->next_vfreg = bb->max_freg;
+
+ /*
+ * FIXME: Need to add more instructions, but the current machine
+ * description can't model some parts of the composite instructions like
+ * cdq.
+ */
+ while (ins) {
+ switch (ins->opcode) {
+ case OP_DIV_IMM:
+ case OP_REM_IMM:
+ case OP_IDIV_IMM:
+ case OP_IREM_IMM:
+ /*
+ * Keep the cases where we could generated optimized
code, otherwise convert
+ * to the non-imm variant.
+ */
+ if (mono_is_power_of_two (ins->inst_imm) >= 0)
+ break;
+
+ NEW_INS (cfg, temp, OP_ICONST);
+ temp->inst_c0 = ins->inst_imm;
+ temp->dreg = mono_regstate_next_int (cfg->rs);
+ switch (ins->opcode) {
+ case OP_DIV_IMM:
+ ins->opcode = OP_LDIV;
+ break;
+ case OP_REM_IMM:
+ ins->opcode = OP_LREM;
+ break;
+ case OP_IDIV_IMM:
+ ins->opcode = OP_IDIV;
+ break;
+ case OP_IREM_IMM:
+ ins->opcode = OP_IREM;
+ break;
+ }
+ ins->sreg2 = temp->dreg;
+ break;
+ default:
+ break;
+ }
+ last_ins = ins;
+ ins = ins->next;
+ }
+ bb->last_ins = last_ins;
+
+ bb->max_ireg = cfg->rs->next_vireg;
+ bb->max_freg = cfg->rs->next_vfreg;
+}
+
static const int
branch_cc_table [] = {
X86_CC_EQ, X86_CC_GE, X86_CC_GT, X86_CC_LE, X86_CC_LT,
@@ -2027,7 +2054,9 @@
/*#include "cprop.c"*/
void
mono_arch_local_regalloc (MonoCompile *cfg, MonoBasicBlock *bb)
-{
+{
+ mono_arch_lowering_pass (cfg, bb);
+
if (cfg->opt & MONO_OPT_PEEPHOLE)
peephole_pass_1 (cfg, bb);
@@ -2606,37 +2635,60 @@
}
break;
case OP_DIV_IMM:
- case OP_IDIV_IMM:
- printf ("A: %d\n", ins->inst_imm);
- x86_push_imm (code, ins->inst_imm);
- x86_cdq (code);
- x86_div_membase (code, X86_ESP, 0, TRUE);
- x86_alu_reg_imm (code, X86_ADD, X86_ESP, 4);
+ case OP_IDIV_IMM: {
+ int power = mono_is_power_of_two (ins->inst_imm);
+
+ g_assert (ins->sreg1 == X86_EAX);
+ g_assert (ins->dreg == X86_EAX);
+ g_assert (power >= 0);
+
+ /* Based on
http://compilers.iecc.com/comparch/article/93-04-079 */
+ if (power == 1) {
+ x86_alu_reg_imm (code, X86_CMP, X86_EAX,
0x80000000);
+ /* Inc %eax, if divident < 0 */
+ x86_alu_reg_imm (code, X86_SBB, X86_EAX, -1);
+ /* Do right shift */
+ x86_shift_reg_imm (code, X86_SAR, X86_EAX, 1);
+ } else {
+ x86_cdq (code);
+ /* Mask correction */
+ x86_alu_reg_imm (code, X86_AND, X86_EDX, (1 <<
power) - 1);
+ /* Apply correction if neccesary */
+ x86_alu_reg_reg (code, X86_ADD, X86_EAX,
X86_EDX);
+ /* Do right shift */
+ x86_shift_reg_imm (code, X86_SAR, X86_EAX,
power);
+ }
break;
+ }
case OP_REM_IMM:
case OP_IREM_IMM: {
int power = mono_is_power_of_two (ins->inst_imm);
- /* FIXME: Add div too */
- /* FIXME: Add tests for these */
- /* FIXME: mono_arch_is_int_overflow () can't handle the
div_imm opcodes */
+ g_assert (ins->sreg1 == X86_EAX);
+ g_assert (ins->dreg == X86_EAX);
+ g_assert (power >= 0);
- /* Based on gcc code */
- switch (power) {
- case 3:
- /* FIXME: Add others */
+ if (power == 1) {
+ /* Based on
http://compilers.iecc.com/comparch/article/93-04-079 */
x86_cdq (code);
+ x86_alu_reg_imm (code, X86_AND, X86_EAX, 1);
+ /*
+ * If the divident is >= 0, this does not
nothing. If it is positive, it
+ * it transforms %eax=0 into %eax=0, and %eax=1
into %eax=-1.
+ */
+ x86_alu_reg_reg (code, X86_XOR, X86_EAX,
X86_EDX);
+ x86_alu_reg_reg (code, X86_SUB, X86_EAX,
X86_EDX);
+ } else {
+ /* Based on gcc code */
+
+ /* Add compensation for negative dividents */
+ x86_cdq (code);
x86_shift_reg_imm (code, X86_SHR, X86_EDX, 32 -
power);
x86_alu_reg_reg (code, X86_ADD, X86_EAX,
X86_EDX);
- x86_alu_reg_imm (code, X86_ADD, X86_EAX, (1 <<
power) - 1);
+ /* Compute remainder */
+ x86_alu_reg_imm (code, X86_AND, X86_EAX, (1 <<
power) - 1);
+ /* Remove compensation */
x86_alu_reg_reg (code, X86_SUB, X86_EAX,
X86_EDX);
- break;
- default:
- x86_push_imm (code, ins->inst_imm);
- x86_cdq (code);
- x86_div_membase (code, X86_ESP, 0, TRUE);
- x86_alu_reg_imm (code, X86_ADD, X86_ESP, 4);
- break;
}
break;
}
_______________________________________________
Mono-patches maillist - [email protected]
http://lists.ximian.com/mailman/listinfo/mono-patches