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

Reply via email to