]> git.unchartedbackwaters.co.uk Git - francis/libjit.git/commitdiff
complete regalloc support for x87
authorAleksey Demakov <ademakov@gmail.com>
Wed, 17 Jan 2007 07:38:47 +0000 (07:38 +0000)
committerAleksey Demakov <ademakov@gmail.com>
Wed, 17 Jan 2007 07:38:47 +0000 (07:38 +0000)
ChangeLog
jit/jit-reg-alloc.c
jit/jit-reg-alloc.h
jit/jit-rules-x86.ins
tools/gen-rules-parser.y

index e5521bb7f88af936521bd4d0a209d44ea7d7c1f7..6882e3cffbcee67adf92b30aa4d56f63d4c6ff81 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,7 +1,17 @@
+2007-01-17  Aleksey Demakov  <ademakov@gmail.com>
+
+       * jit/jit-reg-alloc.h, jit/jit-reg-alloc.c: complete special x87
+       arithmetic support, for other x87 instructions reverse the order of
+       arguments on the stack.
+
+       * jit/jit-rules-x86.ins: take advantage of regalloc's x87 arithmetic
+       support. Also do not clobber the entire x87 stack for atan, sin, and
+       cos rules.
+
 2007-01-12  Heiko Weiss <heiko.weiss@de.trumpf-laser.com>
 
-       * jit/jit-function.c: Fix a typo in jit_function_from_vtable_pointer which
-       breaks the build if libjit is built in interpreter mode.
+       * jit/jit-function.c: Fix a typo in jit_function_from_vtable_pointer
+       which breaks the build if libjit is built in interpreter mode.
 
 2007-01-04  Thomas Cort  <linuxgeek@gmail.com>
 
index b8007a48d72b78ac056e9a6f2acc483ba265a312..173ddd7d57a7f5fa0354c43eb1a948895ee256fc 100644 (file)
@@ -208,6 +208,14 @@ are_values_equal(_jit_regdesc_t *desc1, _jit_regdesc_t *desc2)
        return 0;
 }
 
+static void
+swap_values(_jit_regdesc_t *desc1, _jit_regdesc_t *desc2)
+{
+       _jit_regdesc_t tdesc;
+       tdesc = *desc1;
+       *desc1 = *desc2;
+       *desc2 = tdesc;
+}
 
 /*
  * Get value usage and liveness information. The accurate liveness data is
@@ -869,6 +877,12 @@ compute_spill_cost(jit_gencode_t gen, _jit_regs_t *regs, int reg, int other_reg)
                        }
                }
        }
+
+       if(gen->contents[reg].is_long_start)
+       {
+               return cost * 2;
+       }
+
        if(other_reg >= 0)
        {
                for(index = 0; index < gen->contents[other_reg].num_values; index++)
@@ -911,6 +925,7 @@ compute_spill_cost(jit_gencode_t gen, _jit_regs_t *regs, int reg, int other_reg)
                        }
                }
        }
+
        return cost;
 }
 
@@ -977,6 +992,10 @@ choose_scratch_register(jit_gencode_t gen, _jit_regs_t *regs, int index)
        int suitable_cost;
        int suitable_age;
 
+#ifdef JIT_REG_DEBUG
+       printf("choose_scratch_register(%d)\n", index);
+#endif
+
        regclass = regs->scratch[index].regclass;
 
        suitable_reg = -1;
@@ -990,23 +1009,20 @@ choose_scratch_register(jit_gencode_t gen, _jit_regs_t *regs, int index)
                        continue;
                }
 
-#if ALLOW_CLOBBER_GLOBAL
                if(jit_reg_is_used(gen->permanent, reg))
                {
+#if ALLOW_CLOBBER_GLOBAL
                        use_cost = COST_CLOBBER_GLOBAL;
+#else
+                       continue;
+#endif
                }
                else
                {
                        use_cost = 0;
                }
-#else
-               if(jit_reg_is_used(gen->permanent, reg))
-               {
-                       continue;
-               }
-               use_cost = 0;
-#endif
 
+#if 0
                if(regs->ternary && regs->descs[0].value
                   && thrashes_value(gen, 0, reg, -1, &regs->descs[0]))
                {
@@ -1022,13 +1038,22 @@ choose_scratch_register(jit_gencode_t gen, _jit_regs_t *regs, int index)
                {
                        use_cost += COST_THRASH;
                }
+#endif
 
-               use_cost += compute_spill_cost(gen, regs, reg, -1);
+               if(!jit_reg_is_used(regs->clobber, reg))
+               {
+                       use_cost += compute_spill_cost(gen, regs, reg, -1);
+               }
+
+#ifdef JIT_REG_DEBUG
+               printf("reg = %d, use_cost = %d\n", reg, use_cost);
+#endif
 
                if(use_cost < suitable_cost
                   || (use_cost == suitable_cost
                       && gen->contents[reg].num_values > 0
-                      && gen->contents[reg].age < suitable_age))
+                      && (IS_STACK_REG(reg)
+                          || gen->contents[reg].age < suitable_age)))
                {
                        suitable_reg = reg;
                        suitable_cost = use_cost;
@@ -1056,6 +1081,10 @@ choose_output_register(jit_gencode_t gen, _jit_regs_t *regs)
        int suitable_cost;
        int suitable_age;
 
+#ifdef JIT_REG_DEBUG
+       printf("choose_output_register()\n");
+#endif
+
        regclass = regs->descs[0].regclass;
        need_pair = _jit_regs_needs_long_pair(regs->descs[0].value->type);
 
@@ -1177,7 +1206,7 @@ choose_output_register(jit_gencode_t gen, _jit_regs_t *regs)
                                        use_cost = 0;
                                }
 #ifdef JIT_REG_STACK
-                               else if(regs->x87_arith)
+                               else if(regs->reversible && regs->no_pop)
                                {
                                        use_cost = 0;
                                }
@@ -1197,7 +1226,15 @@ choose_output_register(jit_gencode_t gen, _jit_regs_t *regs)
                        }
                }
 
-               use_cost += compute_spill_cost(gen, regs, reg, other_reg);
+               if(!jit_reg_is_used(regs->clobber, reg)
+                  && !(other_reg >= 0 && jit_reg_is_used(regs->clobber, other_reg)))
+               {
+                       use_cost += compute_spill_cost(gen, regs, reg, other_reg);
+               }
+
+#ifdef JIT_REG_DEBUG
+               printf("reg = %d, other_reg = %d, use_cost = %d\n", reg, other_reg, use_cost);
+#endif
 
                if(use_cost < suitable_cost
                   || (use_cost == suitable_cost
@@ -1223,25 +1260,20 @@ choose_output_register(jit_gencode_t gen, _jit_regs_t *regs)
 /*
  * Select the best argument order for binary ops. The posibility to select
  * the order exists only for commutative ops and for some x87 floating point
- * instructions. Those x87 instructions have variants with reversed argument
- * order or reversed destination register. Also they have variants that
- * either do or do not pop the stack top.
+ * instructions. Those x87 instructions have variants with reversed
+ * destination register.
  */
 static void
 choose_input_order(jit_gencode_t gen, _jit_regs_t *regs)
 {
-       _jit_regdesc_t temp_desc;
-
        if(regs->descs[2].value
           && regs->descs[2].value->in_register
           && regs->descs[2].value->reg == regs->descs[0].reg
           && regs->descs[2].value != regs->descs[1].value)
        {
 #ifdef JIT_REG_STACK
-               if(regs->x87_arith)
+               if(regs->reversible && regs->no_pop)
                {
-                       regs->no_pop = 1;
-                       regs->reverse_dest = 1;
                        regs->dest_input_index = 2;
                }
                else
@@ -1249,9 +1281,7 @@ choose_input_order(jit_gencode_t gen, _jit_regs_t *regs)
                {
                        if(regs->commutative)
                        {
-                               temp_desc = regs->descs[1];
-                               regs->descs[1] = regs->descs[2];
-                               regs->descs[2] = temp_desc;
+                               swap_values(&regs->descs[1], &regs->descs[2]);
                        }
                        regs->dest_input_index = 1;
                }
@@ -1264,41 +1294,6 @@ choose_input_order(jit_gencode_t gen, _jit_regs_t *regs)
        {
                regs->dest_input_index = 0;
        }
-
-#ifdef JIT_REG_STACK
-       /* Choose between pop and no-pop instructions. */
-       if(!regs->no_pop && regs->x87_arith
-          && !regs->clobber_all && !regs->clobber_stack
-          && regs->descs[1].value && regs->descs[2].value)
-       {
-               int keep1, keep2;
-
-               /* Determine if we might want to keep either of input values
-                  in registers after the instruction completion. */
-               if(regs->descs[1].value->in_register)
-               {
-                       keep1 = is_register_alive(gen, regs, regs->descs[1].value->reg);
-               }
-               else
-               {
-                       keep1 = (regs->descs[1].used
-                                && (regs->descs[1].value != regs->descs[0].value)
-                                && !regs->descs[1].clobber);
-               }
-               if(regs->descs[2].value->in_register)
-               {
-                       keep2 = is_register_alive(gen, regs, regs->descs[2].value->reg);
-               }
-               else
-               {
-                       keep2 = (regs->descs[2].used
-                                && (regs->descs[2].value != regs->descs[0].value)
-                                && !regs->descs[2].clobber);
-               }
-
-               regs->no_pop = (keep1 || keep2);
-       }
-#endif
 }
 
 static int
@@ -1315,6 +1310,10 @@ choose_input_register(jit_gencode_t gen, _jit_regs_t *regs, int index)
        int suitable_age;
        int clobber;
 
+#ifdef JIT_REG_DEBUG
+       printf("choose_input_register(%d)\n", index);
+#endif
+
        desc = &regs->descs[index];
        if(!desc->value)
        {
@@ -1410,17 +1409,17 @@ choose_input_register(jit_gencode_t gen, _jit_regs_t *regs, int index)
                                continue;
 #endif
                        }
-                       if(jit_reg_is_used(regs->clobber, reg)
-                          || (other_reg >= 0 && jit_reg_is_used(regs->clobber, other_reg)))
-                       {
-                               /* noop */
-                       }
-                       else
+                       if(!jit_reg_is_used(regs->clobber, reg)
+                          && !(other_reg >= 0 && jit_reg_is_used(regs->clobber, other_reg)))
                        {
                                use_cost += compute_spill_cost(gen, regs, reg, other_reg);
                        }
                }
 
+#ifdef JIT_REG_DEBUG
+               printf("reg = %d, other_reg = %d, use_cost = %d\n", reg, other_reg, use_cost);
+#endif
+
                if(use_cost < suitable_cost
                   || (use_cost == suitable_cost
                       && gen->contents[reg].num_values > 0
@@ -1465,110 +1464,215 @@ check_duplicate_value(_jit_regs_t *regs, _jit_regdesc_t *desc1, _jit_regdesc_t *
 }
 
 #ifdef JIT_REG_STACK
+
+/*
+ * For x87 instructions choose between pop and no-pop variants.
+ */
 static void
-adjust_assignment(jit_gencode_t gen, _jit_regs_t *regs, int index)
+select_nopop_or_pop(jit_gencode_t gen, _jit_regs_t *regs)
 {
-       _jit_regdesc_t *desc;
+       int keep1, keep2;
 
-       desc = &regs->descs[index];
-       if(!desc->value || !IS_STACK_REG(desc->reg))
+       if(!regs->x87_arith || !regs->descs[1].value || !regs->descs[2].value)
        {
                return;
        }
 
-       if(regs->wanted_stack_count == 1)
+       /* Equal values should be assigned to one register and this is
+          going to work only with no-pop instructions. */
+       if(are_values_equal(&regs->descs[1], &regs->descs[2]))
        {
-               /* either a unary op or a binary op with duplicate value */
-               desc->reg = gen->reg_stack_top - regs->loaded_stack_count;
+               regs->no_pop = 1;
+               return;
        }
-       else if(regs->wanted_stack_count == 2)
+
+       /* Determine if we might want to keep input values in registers
+          after the instruction completion. */
+       if(regs->descs[1].value->in_register)
        {
-               /* a binary op */
+               keep1 = is_register_alive(gen, regs, regs->descs[1].value->reg);
+       }
+       else
+       {
+               keep1 = (regs->descs[1].used
+                        && (regs->descs[1].value != regs->descs[0].value)
+                        && !regs->descs[1].clobber);
+       }
+       if(regs->descs[2].value->in_register)
+       {
+               keep2 = is_register_alive(gen, regs, regs->descs[2].value->reg);
+       }
+       else
+       {
+               keep2 = (regs->descs[2].used
+                        && (regs->descs[2].value != regs->descs[0].value)
+                        && !regs->descs[2].clobber);
+       }
 
-               /* find the input value the output goes to */
-               if(index == 0)
-               {
-                       index = regs->dest_input_index;
-               }
+       regs->no_pop = (keep1 || keep2);
+}
+
+static void
+select_stack_order(jit_gencode_t gen, _jit_regs_t *regs)
+{
+       _jit_regdesc_t *desc1;
+       _jit_regdesc_t *desc2;
+       int top_index;
+
+#ifdef JIT_REG_DEBUG
+       printf("select_stack_order()\n");
+#endif
+
+       if(!regs->x87_arith || regs->wanted_stack_count != 2)
+       {
+               return;
+       }
 
-               if(desc->value->in_register && !desc->copy && regs->x87_arith)
+       desc1 = &regs->descs[1];
+       desc2 = &regs->descs[2];
+
+       /* Choose instruction that results into fewer exchanges. If either
+          of two arguments may be on the stack top choose the second to be
+          on top. */
+       /* TODO: See if the next instruction wants the output or remaining
+          input to be on the stack top. */
+       if(desc2->copy || desc2->load)
+       {
+               /* the second argument is going to be on the top */
+               top_index = 2;
+       }
+       else if(desc1->copy || desc1->load)
+       {
+               /* the first argument is going to be on the top */
+               top_index = 1;
+       }
+       else if(desc2->value->reg == (gen->reg_stack_top - 1))
+       {
+               /* the second argument is already on the top */
+               top_index = 2;
+       }
+       else if(desc1->value->reg == (gen->reg_stack_top - 1))
+       {
+               /* the first argument is already on the top */
+               top_index = 1;
+       }
+       else
+       {
+               top_index = 2;
+       }
+
+       if(regs->no_pop)
+       {
+               regs->flip_args = (top_index == 2);
+       }
+       else if(regs->reversible)
+       {
+               if(top_index == 2)
                {
-                       desc->reg = desc->value->reg;
+                       regs->flip_args = 1;
+                       regs->dest_input_index = 1;
                }
                else
                {
-                       desc->reg = gen->reg_stack_top - regs->loaded_stack_count + index - 1;
+                       regs->flip_args = 0;
+                       regs->dest_input_index = 2;
                }
        }
-}
+       else /*if(regs->commutative)*/
+       {
+               regs->flip_args = 1;
+               regs->dest_input_index = 1;
+
+               if(top_index != 2)
+               {
+                       swap_values(&regs->descs[1], &regs->descs[2]);
+               }
+       }
+
+#ifdef JIT_REG_DEBUG
+       printf("top_index = %d, flip_args = %d, dest_input_index = %d\n",
+              top_index, regs->flip_args, regs->dest_input_index);
 #endif
+}
 
-#ifdef JIT_REG_STACK
 static void
-select_stack_order(jit_gencode_t gen, _jit_regs_t *regs)
+adjust_assignment(jit_gencode_t gen, _jit_regs_t *regs, int index)
 {
-       _jit_regdesc_t *desc1;
-       _jit_regdesc_t *desc2;
-       _jit_regdesc_t temp_desc;
-       int top_index;
+       _jit_regdesc_t *desc, *desc2;
+
+#ifdef JIT_REG_DEBUG
+       printf("adjust_assignment(%d)\n", index);
+#endif
 
-       /* Choose instruction that results into fewer exchanges. */
-       if(regs->wanted_stack_count > 1 && regs->no_pop
-          && (regs->commutative || regs->reversible))
+       desc = &regs->descs[index];
+       if(!desc->value || !IS_STACK_REG(desc->reg))
        {
-               desc1 = &regs->descs[1];
-               desc2 = &regs->descs[2];
+               return;
+       }
 
-               if(desc1->value->in_register && !desc1->copy
-                  && desc2->value->in_register && !desc2->copy)
+       if(regs->wanted_stack_count == 1)
+       {
+               /* either a unary op or a binary op with duplicate value */
+               desc->reg = gen->reg_stack_top - regs->loaded_stack_count;
+       }
+       else if(regs->wanted_stack_count == 2)
+       {
+               /* a binary op */
+
+               /* find the input value the output goes to */
+               if(index == 0)
                {
-                       /* Is any of the input values on the stack top? */
-                       if(desc1->value->reg == (gen->reg_stack_top - 1))
+                       if(regs->x87_arith)
                        {
-                               top_index = 1;
-                       }
-                       else if(desc2->value->reg == (gen->reg_stack_top - 1))
-                       {
-                               top_index = 2;
+                               index = regs->dest_input_index;
                        }
                        else
                        {
-                               /* TODO: See if the next instruction wants output
-                                  or remaining input to be on the stack top. */
-                               top_index = 2;
+                               index = 2;
                        }
+                       desc2 = &regs->descs[index];
                }
-               else if(desc1->value->in_register && !desc1->copy)
+               else
                {
-                       top_index = 2;
+                       desc2 = desc;
                }
-               else if(desc2->value->in_register && !desc2->copy)
+
+               if(regs->flip_args)
                {
-                       top_index = 1;
+                       if(regs->x87_arith && index == 1
+                          && desc2->value->in_register && !desc2->copy)
+                       {
+                               desc->reg = desc2->value->reg;
+                       }
+                       else
+                       {
+                               desc->reg = (gen->reg_stack_top
+                                            - regs->loaded_stack_count
+                                            + index - 1);
+                       }
                }
                else
                {
-                       /* TODO: see if the next instruction wants output or remaining
-                          input to be on the stack top. */
-                       top_index = 2;
-               }
-
-               if(top_index == 1)
-               {
-                       if(regs->reversible)
+                       if(regs->x87_arith && index == 2
+                          && desc2->value->in_register && !desc2->copy)
                        {
-                               regs->reverse_args = 1;
+                               desc->reg = desc2->value->reg;
                        }
-                       else /*if(regs->commutative)*/
+                       else
                        {
-                               temp_desc = *desc1;
-                               *desc1 = *desc2;
-                               *desc2 = temp_desc;
+                               desc->reg = (gen->reg_stack_top
+                                            - regs->loaded_stack_count
+                                            + regs->wanted_stack_count
+                                            - index);
                        }
-                       regs->reverse_dest ^= 1;
                }
        }
+
+#ifdef JIT_REG_DEBUG
+       printf("reg = %d\n", desc->reg);
+#endif
 }
+
 #endif
 
 /*
@@ -2281,17 +2385,45 @@ abort_input_value(jit_gencode_t gen, _jit_regs_t *regs, int index)
        }
 }
 
+#ifdef JIT_REG_STACK
 static void
-commit_input_value(jit_gencode_t gen, _jit_regs_t *regs, int index, int go_down_stack)
+pop_input_value(jit_gencode_t gen, _jit_regs_t *regs, int index)
 {
        _jit_regdesc_t *desc;
-       int reg, other_reg;
-#ifdef JIT_REG_STACK
-       int is_down_stack = 0;
+
+#ifdef JIT_REG_DEBUG
+       printf("pop_input_value(%d)\n", index);
 #endif
 
+       desc = &regs->descs[index];
+       if(!desc->value || desc->duplicate)
+       {
+               return;
+       }
+
+       if(IS_STACK_REG(desc->reg))
+       {
+               if(desc->copy)
+               {
+                       gen->contents[desc->reg].used_for_temp = 0;
+               }
+               else
+               {
+                       unbind_value(gen, desc->value, desc->reg, 0);
+               }
+               --(gen->reg_stack_top);
+       }
+}
+#endif
+
+static void
+commit_input_value(jit_gencode_t gen, _jit_regs_t *regs, int index, int killed)
+{
+       _jit_regdesc_t *desc;
+       int reg, other_reg;
+
 #ifdef JIT_REG_DEBUG
-       printf("commit_input_value(%d, %d)\n", index, go_down_stack);
+       printf("commit_input_value(%d)\n", index);
 #endif
 
        desc = &regs->descs[index];
@@ -2300,20 +2432,19 @@ commit_input_value(jit_gencode_t gen, _jit_regs_t *regs, int index, int go_down_
                return;
        }
 
+#ifdef JIT_REG_STACK
+       if(!IS_STACK_REG(desc->reg))
+       {
+               killed = 0;
+       }
+#endif
+
        if(desc->copy)
        {
 #ifdef JIT_REG_STACK
-               if(IS_STACK_REG(desc->reg))
+               if(killed)
                {
-                       if(!go_down_stack)
-                       {
-                               if(1/*!regs->copy*/)
-                               {
-                                       --(gen->reg_stack_top);
-                               }
-                               gen->contents[desc->reg].used_for_temp = 0;
-                       }
-                       is_down_stack = 1;
+                       killed = 0;
                }
                else
 #endif
@@ -2327,7 +2458,7 @@ commit_input_value(jit_gencode_t gen, _jit_regs_t *regs, int index, int go_down_
        }
 
 #ifdef JIT_REG_STACK
-       if(desc->kill && desc->value->in_register && is_down_stack == go_down_stack)
+       if(!killed && desc->kill && desc->value->in_register)
 #else
        if(desc->kill && desc->value->in_register)
 #endif
@@ -2341,22 +2472,7 @@ commit_input_value(jit_gencode_t gen, _jit_regs_t *regs, int index, int go_down_
                {
                        other_reg = -1;
                }
-#ifdef JIT_REG_STACK
-               if(is_down_stack)
-               {
-                       free_value(gen, desc->value, reg, other_reg, 0);
-               }
-               else
-               {
-                       unbind_value(gen, desc->value, reg, other_reg);
-                       if(IS_STACK_REG(reg) /*&& !regs->copy*/)
-                       {
-                               --(gen->reg_stack_top);
-                       }
-               }
-#else
-               unbind_value(gen, desc->value, reg, other_reg);
-#endif
+               free_value(gen, desc->value, reg, other_reg, 0);
        }
 
 #ifdef JIT_REG_DEBUG
@@ -2372,7 +2488,7 @@ commit_input_value(jit_gencode_t gen, _jit_regs_t *regs, int index, int go_down_
 }
 
 static void
-commit_output_value(jit_gencode_t gen, _jit_regs_t *regs)
+commit_output_value(jit_gencode_t gen, _jit_regs_t *regs, int push_stack_top)
 {
        _jit_regdesc_t *desc;
 
@@ -2386,12 +2502,10 @@ commit_output_value(jit_gencode_t gen, _jit_regs_t *regs)
                return;
        }
 
-#ifdef JIT_REG_STACK
-       if(IS_STACK_REG(desc->reg) /*&& !regs->copy*/)
+       if(IS_STACK_REG(desc->reg) && push_stack_top)
        {
                ++(gen->reg_stack_top);
        }
-#endif
        bind_value(gen, desc->value, desc->reg, desc->other_reg, 0);
 
        if(!desc->used)
@@ -3138,13 +3252,6 @@ _jit_regs_clobber_class(jit_gencode_t gen, _jit_regs_t *regs, _jit_regclass_t *r
 {
        int index;
 
-#ifdef JIT_REG_STACK
-       if((regclass->flags & JIT_REG_IN_STACK) != 0)
-       {
-               regs->clobber_stack = 1;
-       }
-#endif
-
        for(index = 0; index < regclass->num_regs; index++)
        {
                if(jit_reg_is_used(gen->permanent, index))
@@ -3160,8 +3267,6 @@ _jit_regs_clobber_all(jit_gencode_t gen, _jit_regs_t *regs)
 {
        int index;
 
-       regs->clobber_all = 1;
-
        for(index = 0; index < JIT_NUM_REGS; index++)
        {
                if((_jit_reg_info[index].flags & JIT_REG_FIXED) != 0)
@@ -3189,54 +3294,52 @@ _jit_regs_assign(jit_gencode_t gen, _jit_regs_t *regs)
           the output always goes to the same register as the first input
           value unless this is a three-address instruction. */
        if(!regs->ternary && !regs->free_dest
-          && regs->descs[0].value
-          && regs->descs[1].value)
+          && regs->descs[0].value && regs->descs[0].reg < 0
+          && regs->descs[1].value && regs->descs[1].reg >= 0)
        {
-               if(regs->descs[0].reg >= 0)
-               {
-                       if(regs->descs[1].reg < 0)
-                       {
-                               set_regdesc_register(gen, regs, 1,
-                                                    regs->descs[0].reg,
-                                                    regs->descs[0].other_reg);
-                       }
-               }
-               else if(regs->descs[1].reg >= 0)
-               {
-                       set_regdesc_register(gen, regs, 0,
-                                            regs->descs[1].reg,
-                                            regs->descs[1].other_reg);
-               }
+               set_regdesc_register(gen, regs, 0,
+                                    regs->descs[1].reg,
+                                    regs->descs[1].other_reg);
        }
 
+#if JIT_REG_STACK
+       /* Choose between x87 pop and no-pop instructions.  */
+       select_nopop_or_pop(gen, regs);
+#endif
+
        /* Assign output and input registers. */
-       if(regs->descs[0].value && regs->descs[0].reg < 0)
+       if(regs->descs[0].value)
        {
-               if(regs->ternary)
+               if(regs->descs[0].reg < 0)
                {
-                       if(!choose_input_register(gen, regs, 0))
+                       if(regs->ternary)
                        {
-                               return 0;
+                               if(!choose_input_register(gen, regs, 0))
+                               {
+                                       return 0;
+                               }
+                       }
+                       else
+                       {
+                               if(!choose_output_register(gen, regs))
+                               {
+                                       return 0;
+                               }
                        }
+               }
+               if(regs->ternary)
+               {
                        check_duplicate_value(regs, &regs->descs[0], &regs->descs[1]);
                        check_duplicate_value(regs, &regs->descs[0], &regs->descs[2]);
                }
-               else
+               else if(!regs->free_dest)
                {
-                       if(!choose_output_register(gen, regs))
+                       choose_input_order(gen, regs);
+                       if(regs->dest_input_index)
                        {
-                               return 0;
-                       }
-                       if(!regs->free_dest)
-                       {
-                               choose_input_order(gen, regs);
-                               if(regs->dest_input_index)
-                               {
-                                       set_regdesc_register(gen, regs,
-                                                            regs->dest_input_index,
-                                                            regs->descs[0].reg,
-                                                            regs->descs[0].other_reg);
-                               }
+                               set_regdesc_register(gen, regs, regs->dest_input_index,
+                                                    regs->descs[0].reg,
+                                                    regs->descs[0].other_reg);
                        }
                }
        }
@@ -3377,38 +3480,54 @@ _jit_regs_gen(jit_gencode_t gen, _jit_regs_t *regs)
        if(regs->wanted_stack_count > 0)
        {
                /* Adjust assignment of stack registers. */
-               adjust_assignment(gen, regs, 0);
-               adjust_assignment(gen, regs, 1);
-               adjust_assignment(gen, regs, 2);
-
                select_stack_order(gen, regs);
+               adjust_assignment(gen, regs, 2);
+               adjust_assignment(gen, regs, 1);
+               adjust_assignment(gen, regs, 0);
 
-               /* Shuffle the values that are already on the register stack. */
-               if(regs->loaded_stack_count > 0 && !regs->x87_arith)
+               if(regs->ternary)
                {
-                       move_input_value(gen, regs, 1);
-                       move_input_value(gen, regs, 2);
+                       /* Ternary ops with only one stack register are supported. */
+                       if(regs->loaded_stack_count > 0)
+                       {
+                               move_input_value(gen, regs, 0);
+                               move_input_value(gen, regs, 1);
+                               move_input_value(gen, regs, 2);
+                       }
+                       else
+                       {
+                               load_input_value(gen, regs, 0);
+                               load_input_value(gen, regs, 1);
+                               load_input_value(gen, regs, 2);
+                       }
                }
-
-               /* Load and shuffle the remaining values. */
-               if(regs->reverse_args)
+               else if(regs->flip_args)
                {
-                       load_input_value(gen, regs, 2);
-                       move_input_value(gen, regs, 2);
+                       /* Shuffle the values that are already on the register stack. */
+                       if(regs->loaded_stack_count > 0)
+                       {
+                               move_input_value(gen, regs, 1);
+                               move_input_value(gen, regs, 2);
+                       }
+
+                       /* Load and shuffle the remaining values. */
                        load_input_value(gen, regs, 1);
                        move_input_value(gen, regs, 1);
+                       load_input_value(gen, regs, 2);
                }
                else
                {
-                       if(regs->ternary)
+                       /* Shuffle the values that are already on the register stack. */
+                       if(regs->loaded_stack_count > 0)
                        {
-                               load_input_value(gen, regs, 0);
-                               move_input_value(gen, regs, 0);
+                               move_input_value(gen, regs, 2);
+                               move_input_value(gen, regs, 1);
                        }
-                       load_input_value(gen, regs, 1);
-                       move_input_value(gen, regs, 1);
+
+                       /* Load and shuffle the remaining values. */
                        load_input_value(gen, regs, 2);
                        move_input_value(gen, regs, 2);
+                       load_input_value(gen, regs, 1);
                }
        }
        else
@@ -3440,15 +3559,14 @@ _jit_regs_select(_jit_regs_t *regs)
        {
                flags |= _JIT_REGS_NO_POP;
        }
-       if(regs->reverse_dest)
+       if(regs->flip_args)
        {
-               flags |= _JIT_REGS_REVERSE_DEST;
+               flags |= _JIT_REGS_FLIP_ARGS;
        }
-       if(regs->reverse_args)
+       if(regs->dest_input_index == 2)
        {
-               flags |= _JIT_REGS_REVERSE_ARGS;
+               flags |= _JIT_REGS_REVERSE;
        }
-
        return flags;
 }
 #endif
@@ -3462,75 +3580,105 @@ _jit_regs_commit(jit_gencode_t gen, _jit_regs_t *regs)
        dump_regs(gen, "enter _jit_regs_commit");
 #endif
 
-#ifdef JIT_REG_STACK
-       if(regs->wanted_stack_count > 0)
+       if(regs->ternary)
        {
-               int reg1, reg2;
-
-               /* The stack registers has to be freed from the top down. It is
-                  assumed that only binary instructions may have more than one
-                  stack register. The unary instruction may not do that for
-                  obvious reasons. The practical observation is that no ternary
-                  instruction in libjit does that as well. */
-               if(regs->reverse_args)
+#ifdef JIT_REG_STACK
+               if(regs->wanted_stack_count > 0)
                {
-                       commit_input_value(gen, regs, 1, 0);
-                       commit_input_value(gen, regs, 2, 0);
+                       pop_input_value(gen, regs, 0);
+                       pop_input_value(gen, regs, 1);
+                       pop_input_value(gen, regs, 2);
                }
-               else
+#endif
+               commit_input_value(gen, regs, 0, 1);
+               commit_input_value(gen, regs, 1, 1);
+               commit_input_value(gen, regs, 2, 1);
+       }
+       else if(!regs->descs[0].value)
+       {
+#ifdef JIT_REG_STACK
+               if(regs->wanted_stack_count > 0)
                {
-                       commit_input_value(gen, regs, 2, 0);
-                       commit_input_value(gen, regs, 1, 0);
+                       pop_input_value(gen, regs, 1);
+                       pop_input_value(gen, regs, 2);
                }
-               if(regs->ternary)
+#endif
+               commit_input_value(gen, regs, 1, 1);
+               commit_input_value(gen, regs, 2, 1);
+       }
+#ifdef JIT_REG_STACK
+       else if(regs->wanted_stack_count > 0)
+       {
+               int pop1, pop2;
+               struct _jit_value temp;
+               int reg1, reg2;
+
+               pop1 = pop2 = 0;
+               if(!regs->no_pop)
                {
-                       commit_input_value(gen, regs, 0, 0);
+                       if(regs->x87_arith)
+                       {
+                               if(regs->flip_args)
+                               {
+                                       pop_input_value(gen, regs, 2);
+                                       pop2 = 1;
+                               }
+                               else
+                               {
+                                       pop_input_value(gen, regs, 1);
+                                       pop1 = 1;
+                               }
+                       }
+                       else
+                       {
+                               pop_input_value(gen, regs, 1);
+                               pop_input_value(gen, regs, 2);
+                               pop1 = pop2 = 1;
+                       }
                }
-               else
+
+               if(IS_STACK_REG(regs->descs[0].reg))
                {
-                       commit_output_value(gen, regs);
+                       temp = *regs->descs[0].value;
+                       if(!regs->x87_arith && !regs->copy)
+                       {
+                               ++(gen->reg_stack_top);
+                       }
+                       bind_value(gen, &temp, regs->descs[0].reg, -1, 0);
                }
 
-               /* If the allocator makes a copy of a value that was already on
-                  the stack we might need to free the original register as well.
-                  In general, the allocator makes a copy if the value is going
-                  to be destroyed by the instruction while it is still used
-                  (according to the liveness analysis). But the original value
-                  needs to be freed only if it is no longer used. So this extra
-                  code seems useless. But there were cases when the allocator
-                  miscalculated the cost of spilling and made a copy when it
-                  was not needed. So this code serves as a precaution against
-                  such problematic cases. */
                reg1 = ((regs->descs[1].value && regs->descs[1].value->in_register)
                        ? regs->descs[1].value->reg : -1);
                reg2 = ((regs->descs[2].value && regs->descs[2].value->in_register)
                        ? regs->descs[2].value->reg : -1);
                if(reg1 > reg2)
                {
-                       commit_input_value(gen, regs, 1, 1);
-                       commit_input_value(gen, regs, 2, 1);
+                       commit_input_value(gen, regs, 1, pop1);
+                       commit_input_value(gen, regs, 2, pop2);
                }
                else
                {
-                       commit_input_value(gen, regs, 2, 1);
-                       commit_input_value(gen, regs, 1, 1);
+                       commit_input_value(gen, regs, 2, pop2);
+                       commit_input_value(gen, regs, 1, pop1);
                }
+
+               if(IS_STACK_REG(regs->descs[0].reg))
+               {
+                       reg1 = temp.reg;
+                       free_value(gen, &temp, reg1, -1, 1);
+                       regs->descs[0].reg = reg1;
+                       regs->descs[0].other_reg = -1;
+               }
+               commit_output_value(gen, regs, 0);
        }
        else
 #endif
        {
                commit_input_value(gen, regs, 2, 0);
                commit_input_value(gen, regs, 1, 0);
-               if(regs->ternary)
-               {
-                       commit_input_value(gen, regs, 0, 0);
-               }
-               else
-               {
-                       commit_output_value(gen, regs);
-               }
+               commit_output_value(gen, regs, 1);
        }
-
+       
        /* Load clobbered global registers. */
        for(reg = JIT_NUM_REGS - 1; reg >= 0; reg--)
        {
index e163b74665e8b5985dc2b3fb841d8a1b6cfc4e70..083d753fcc5ae8586124362e00d11e9130225df4 100644 (file)
@@ -61,8 +61,8 @@ extern        "C" {
  * Flags returned by _jit_regs_select_insn().
  */
 #define _JIT_REGS_NO_POP               0x0001
-#define _JIT_REGS_REVERSE_DEST         0x0002
-#define _JIT_REGS_REVERSE_ARGS         0x0004
+#define _JIT_REGS_FLIP_ARGS            0x0002
+#define _JIT_REGS_REVERSE              0x0004
 
 /*
  * Contains register assignment data for single operand.
@@ -106,8 +106,6 @@ typedef struct
        _jit_scratch_t  scratch[_JIT_REGS_SCRATCH_MAX];
        int             num_scratch;
 
-       unsigned        clobber_all : 1;
-
        unsigned        ternary : 1;
        unsigned        branch : 1;
        unsigned        copy : 1;
@@ -118,11 +116,9 @@ typedef struct
        unsigned        on_stack : 1;
        unsigned        x87_arith : 1;
        unsigned        reversible : 1;
-       unsigned        clobber_stack : 1;
 
        unsigned        no_pop : 1;
-       unsigned        reverse_dest : 1;
-       unsigned        reverse_args : 1;
+       unsigned        flip_args : 1;
 #endif
 
        /* The input value index that is going to be overwritten
index b8aa10ade50b8e54feb4240133c144a283ebedfe..78717b2b9b976802fa58fa4388a4783097a3c120 100644 (file)
@@ -749,30 +749,146 @@ JIT_OP_LNEG:
 #endif
        }
 
-JIT_OP_FADD, JIT_OP_DADD, JIT_OP_NFADD: stack
+JIT_OP_FADD, JIT_OP_DADD, JIT_OP_NFADD: stack, x87_arith, commutative
        [freg, freg] -> {
-               x86_fp_op_reg(inst, X86_FADD, 1, 1);
+               int flags;
+
+               flags = _jit_regs_select(&regs);
+
+               if((flags & _JIT_REGS_NO_POP) == 0)
+               {
+                       x86_fp_op_reg(inst, X86_FADD,
+                               fp_stack_index(gen, $1 + JIT_REG_STACK_START), 1);
+               }
+               else if((flags & _JIT_REGS_FLIP_ARGS) != 0)
+               {
+                       x86_fp_op_reg(inst, X86_FADD,
+                               fp_stack_index(gen, $1 + JIT_REG_STACK_START), 0);
+               }
+               else
+               {
+                       x86_fp_op(inst, X86_FADD,
+                               fp_stack_index(gen, $2 + JIT_REG_STACK_START));
+               }
        }
 
-JIT_OP_FSUB, JIT_OP_DSUB, JIT_OP_NFSUB: stack
+JIT_OP_FSUB, JIT_OP_DSUB, JIT_OP_NFSUB: stack, x87_arith_reversible
        [freg, freg] -> {
-               x86_fp_op_reg(inst, X86_FSUB, 1, 1);
+               int flags;
+
+               flags = _jit_regs_select(&regs);
+
+               if((flags & _JIT_REGS_NO_POP) == 0)
+               {
+                       if((flags & _JIT_REGS_REVERSE) == 0)
+                       {
+                               x86_fp_op_reg(inst, X86_FSUB,
+                                       fp_stack_index(gen, $1 + JIT_REG_STACK_START), 1);
+                       }
+                       else
+                       {
+                               x86_fp_op_reg(inst, X86_FSUBR,
+                                       fp_stack_index(gen, $2 + JIT_REG_STACK_START), 1);
+                       }
+               }
+               else if((flags & _JIT_REGS_FLIP_ARGS) != 0)
+               {
+                       if((flags & _JIT_REGS_REVERSE) == 0)
+                       {
+                               x86_fp_op_reg(inst, X86_FSUB,
+                                       fp_stack_index(gen, $1 + JIT_REG_STACK_START), 0);
+                       }
+                       else
+                       {
+                               x86_fp_op(inst, X86_FSUBR,
+                                       fp_stack_index(gen, $1 + JIT_REG_STACK_START));
+                       }
+               }
+               else
+               {
+                       if((flags & _JIT_REGS_REVERSE) == 0)
+                       {
+                               x86_fp_op(inst, X86_FSUB,
+                                       fp_stack_index(gen, $2 + JIT_REG_STACK_START));
+                       }
+                       else
+                       {
+                               x86_fp_op_reg(inst, X86_FSUBR,
+                                       fp_stack_index(gen, $2 + JIT_REG_STACK_START), 0);
+                       }
+               }
        }
 
-JIT_OP_FMUL, JIT_OP_DMUL, JIT_OP_NFMUL: stack
+JIT_OP_FMUL, JIT_OP_DMUL, JIT_OP_NFMUL: stack, x87_arith, commutative
        [freg, freg] -> {
-               x86_fp_op_reg(inst, X86_FMUL, 1, 1);
+               int flags;
+
+               flags = _jit_regs_select(&regs);
+
+               if((flags & _JIT_REGS_NO_POP) == 0)
+               {
+                       x86_fp_op_reg(inst, X86_FMUL, fp_stack_index(gen, $1 + JIT_REG_STACK_START), 1);
+               }
+               else if((flags & _JIT_REGS_FLIP_ARGS) != 0)
+               {
+                       x86_fp_op_reg(inst, X86_FMUL, fp_stack_index(gen, $1 + JIT_REG_STACK_START), 0);
+               }
+               else
+               {
+                       x86_fp_op(inst, X86_FMUL, fp_stack_index(gen, $2 + JIT_REG_STACK_START));
+               }
        }
 
-JIT_OP_FDIV, JIT_OP_DDIV, JIT_OP_NFDIV: stack
+JIT_OP_FDIV, JIT_OP_DDIV, JIT_OP_NFDIV: stack, x87_arith_reversible
        [freg, freg] -> {
-               x86_fp_op_reg(inst, X86_FDIV, 1, 1);
+               int flags;
+
+               flags = _jit_regs_select(&regs);
+
+               if((flags & _JIT_REGS_NO_POP) == 0)
+               {
+                       if((flags & _JIT_REGS_REVERSE) == 0)
+                       {
+                               x86_fp_op_reg(inst, X86_FDIV,
+                                       fp_stack_index(gen, $1 + JIT_REG_STACK_START), 1);
+                       }
+                       else
+                       {
+                               x86_fp_op_reg(inst, X86_FDIVR,
+                                       fp_stack_index(gen, $2 + JIT_REG_STACK_START), 1);
+                       }
+               }
+               else if((flags & _JIT_REGS_FLIP_ARGS) != 0)
+               {
+                       if((flags & _JIT_REGS_REVERSE) == 0)
+                       {
+                               x86_fp_op_reg(inst, X86_FDIV,
+                                       fp_stack_index(gen, $1 + JIT_REG_STACK_START), 0);
+                       }
+                       else
+                       {
+                               x86_fp_op(inst, X86_FDIVR,
+                                       fp_stack_index(gen, $1 + JIT_REG_STACK_START));
+                       }
+               }
+               else
+               {
+                       if((flags & _JIT_REGS_REVERSE) == 0)
+                       {
+                               x86_fp_op(inst, X86_FDIV,
+                                       fp_stack_index(gen, $2 + JIT_REG_STACK_START));
+                       }
+                       else
+                       {
+                               x86_fp_op_reg(inst, X86_FDIVR,
+                                       fp_stack_index(gen, $2 + JIT_REG_STACK_START), 0);
+                       }
+               }
        }
 
 JIT_OP_FREM, JIT_OP_DREM, JIT_OP_NFREM: stack
        [freg, freg, scratch reg("eax")] -> {
                unsigned char *label;
-               x86_fxch(inst, 1);
                label = inst;
                x86_fprem(inst);
                x86_fnstsw(inst);
@@ -1232,7 +1348,7 @@ JIT_OP_IGE_UN:
  */
 
 JIT_OP_FATAN, JIT_OP_DATAN, JIT_OP_NFATAN: stack
-       [freg, clobber(freg)] -> {
+       [freg, scratch freg] -> {
                x86_fld1(inst);
                x86_fpatan(inst);
                x86_fldz(inst);
@@ -1240,14 +1356,14 @@ JIT_OP_FATAN, JIT_OP_DATAN, JIT_OP_NFATAN: stack
        }
 
 JIT_OP_FCOS, JIT_OP_DCOS, JIT_OP_NFCOS: stack
-       [freg, clobber(freg)] -> {
+       [freg, scratch freg] -> {
                x86_fcos(inst);
                x86_fldz(inst);
                x86_fp_op_reg(inst, X86_FADD, 1, 1);
        }
 
 JIT_OP_FSIN, JIT_OP_DSIN, JIT_OP_NFSIN: stack
-       [freg, clobber(freg)] -> {
+       [freg, scratch freg] -> {
                x86_fsin(inst);
                x86_fldz(inst);
                x86_fp_op_reg(inst, X86_FADD, 1, 1);
@@ -2073,7 +2189,7 @@ JIT_OP_STORE_RELATIVE_LONG: ternary
                x86_mov_membase_reg(inst, $1, $3 + 4, %2, 4);
        }
 
-JIT_OP_STORE_RELATIVE_FLOAT32: ternary
+JIT_OP_STORE_RELATIVE_FLOAT32: ternary, stack
        [reg, imm, imm] -> {
                x86_mov_membase_imm(inst, $1, $3, ((int *)($2))[0], 4);
        }
@@ -2081,7 +2197,7 @@ JIT_OP_STORE_RELATIVE_FLOAT32: ternary
                x86_fst_membase(inst, $1, $3, 0, 1);
        }
 
-JIT_OP_STORE_RELATIVE_FLOAT64: ternary
+JIT_OP_STORE_RELATIVE_FLOAT64: ternary, stack
        [reg, imm, imm] -> {
                x86_mov_membase_imm(inst, $1, $3, ((int *)($2))[0], 4);
                x86_mov_membase_imm(inst, $1, $3 + 4, ((int *)($2))[1], 4);
@@ -2090,7 +2206,7 @@ JIT_OP_STORE_RELATIVE_FLOAT64: ternary
                x86_fst_membase(inst, $1, $3, 1, 1);
        }
 
-JIT_OP_STORE_RELATIVE_NFLOAT: ternary
+JIT_OP_STORE_RELATIVE_NFLOAT: ternary, stack
        [reg, imm, imm] -> {
                x86_mov_membase_imm(inst, $1, $3, ((int *)($2))[0], 4);
                x86_mov_membase_imm(inst, $1, $3 + 4, ((int *)($2))[1], 4);
@@ -2235,17 +2351,17 @@ JIT_OP_STORE_ELEMENT_LONG: ternary
                x86_mov_memindex_reg(inst, $1, 4, $2, 3, %3, 4);
        }
 
-JIT_OP_STORE_ELEMENT_FLOAT32: ternary
+JIT_OP_STORE_ELEMENT_FLOAT32: ternary, stack
        [reg, reg, freg] -> {
                x86_fst_memindex(inst, $1, 0, $2, 2, 0, 1);
        }
 
-JIT_OP_STORE_ELEMENT_FLOAT64: ternary
+JIT_OP_STORE_ELEMENT_FLOAT64: ternary, stack
        [reg, reg, freg] -> {
                x86_fst_memindex(inst, $1, 0, $2, 3, 1, 1);
        }
 
-JIT_OP_STORE_ELEMENT_NFLOAT: ternary
+JIT_OP_STORE_ELEMENT_NFLOAT: ternary, stack
        [reg, +reg, freg, if("sizeof(jit_nfloat) != sizeof(jit_float64)")] -> {
                /* lea reg2, [reg2 + reg2 * 2]  */
                x86_lea_memindex(inst, $2, $2, 0, $2, 1);
index 22384baf2d7669d19ff4c34bc7e34fde1bcf70e9..ea9513594dc495ab74b475cb0a79c6f243eeebff 100644 (file)
@@ -1239,7 +1239,7 @@ static void gensel_output_clauses(gensel_clause_t clauses, gensel_option_t optio
                                {
                                        seen_option = 1;
                                }
-                               printf("_JIT_REGS_X87_ARITH_REVERSIBLE");
+                               printf("_JIT_REGS_X87_ARITH | _JIT_REGS_REVERSIBLE");
                        }
                        if(!seen_option)
                        {