dotgnu-pnet-commits
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[dotgnu-pnet-commits] libjit ./ChangeLog jit/jit-reg-alloc.h jit/jit-...


From: Aleksey Demakov
Subject: [dotgnu-pnet-commits] libjit ./ChangeLog jit/jit-reg-alloc.h jit/jit-...
Date: Fri, 14 Apr 2006 11:46:05 +0000

CVSROOT:        /sources/dotgnu-pnet
Module name:    libjit
Branch:         
Changes by:     Aleksey Demakov <address@hidden>        06/04/14 11:46:05

Modified files:
        .              : ChangeLog 
        jit            : jit-reg-alloc.h jit-reg-alloc.c 

Log message:
        new register allocator is improved and extended to support stack 
registers

CVSWeb URLs:
http://cvs.savannah.gnu.org/viewcvs/dotgnu-pnet/libjit/ChangeLog.diff?tr1=1.215&tr2=1.216&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/dotgnu-pnet/libjit/jit/jit-reg-alloc.h.diff?tr1=1.7&tr2=1.8&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/dotgnu-pnet/libjit/jit/jit-reg-alloc.c.diff?tr1=1.21&tr2=1.22&r1=text&r2=text

Patches:
Index: libjit/ChangeLog
diff -u libjit/ChangeLog:1.215 libjit/ChangeLog:1.216
--- libjit/ChangeLog:1.215      Mon Apr 10 19:42:40 2006
+++ libjit/ChangeLog    Fri Apr 14 11:46:05 2006
@@ -1,3 +1,8 @@
+2006-04-14  Aleksey Demakov  <address@hidden>
+
+       * jit/jit-reg-alloc.h, jit/jit-reg-alloc.c: new register allocator
+       improved and extended to support stack registers.
+
 2006-04-11  Aleksey Demakov  <address@hidden>
 
        * jit/jit-insn.c (jit_insn_start_catcher): initialize
Index: libjit/jit/jit-reg-alloc.c
diff -u libjit/jit/jit-reg-alloc.c:1.21 libjit/jit/jit-reg-alloc.c:1.22
--- libjit/jit/jit-reg-alloc.c:1.21     Sat Feb 18 19:58:10 2006
+++ libjit/jit/jit-reg-alloc.c  Fri Apr 14 11:46:05 2006
@@ -22,6 +22,7 @@
 #include "jit-reg-alloc.h"
 #include <jit/jit-dump.h>
 #include <stdio.h>
+#include <string.h>
 
 /*@
 
@@ -1632,35 +1633,43 @@
  * New Reg Alloc API
  */
 
+#define IS_STACK_REG(reg)      ((_jit_reg_info[reg].flags & JIT_REG_IN_STACK) 
!= 0)
+#define IS_STACK_START(reg)    ((_jit_reg_info[reg].flags & 
JIT_REG_START_STACK) != 0)
+#define IS_STACK_END(reg)      ((_jit_reg_info[reg].flags & JIT_REG_END_STACK) 
!= 0)
+#define OTHER_REG(reg)         (_jit_reg_info[reg].other_reg)
+
+/* The cost value that precludes using the register in question. */
+#define COST_TOO_MUCH          1000000
+
+/* Value usage flags. */
+#define VALUE_INPUT            1
+#define VALUE_OUTPUT           2
+#define VALUE_USED             4
+
 /*
- * Set assigned and clobbered flags for register.
+ * For a stack register find the first stack register.
  */
-static void
-set_register_bits(_jit_regs_t *regs, _jit_regdesc_t *desc, int output)
+static int
+get_stack_start(int reg)
 {
-       int clobber;
-       if(desc->reg >= 0)
+       if(IS_STACK_REG(reg))
        {
-               clobber = desc->clobber;
-               if(output && desc->value->in_register && desc->value->reg == 
desc->reg)
+               while(!IS_STACK_START(reg))
                {
-                       clobber = 0;
+                       --reg;
                }
+       }
+       return reg;
+}
 
-               jit_reg_set_used(regs->assigned, desc->reg);
-               if(clobber)
-               {
-                       jit_reg_set_used(regs->clobber, desc->reg);
-               }
-               if(desc->other_reg >= 0)
-               {
-                       jit_reg_set_used(regs->assigned, desc->other_reg);
-                       if(clobber)
-                       {
-                               jit_reg_set_used(regs->clobber, 
desc->other_reg);
-                       }
-               }
+static int
+get_stack_size(jit_gencode_t gen, int stack_start)
+{
+       if(gen->contents[stack_start].remap < 0)
+       {
+               return 0;
        }
+       return (gen->contents[stack_start].remap - stack_start + 1);
 }
 
 /*
@@ -1701,127 +1710,330 @@
 }
 
 /*
- * Assign diplicate input value to the same register if possible.
- * The first value has to be already assigned. The second value
- * is assigned to the same register if it is equal to the first
- * and neither of them is clobbered.
+ * Check if the value is one of the input values.
  */
-static void
-reuse_duplicate_value(_jit_regdesc_t *desc1, _jit_regdesc_t *desc2)
+static int
+value_usage(_jit_regs_t *regs, jit_value_t value)
 {
-       if(desc1->value == desc2->value
-          && desc1->reg >= 0 && desc2->reg < 0
-          && !desc1->clobber && !desc2->clobber)
+       int flags = 0;
+       if(value == regs->descs[0].value)
        {
-               desc2->reg = desc1->reg;
-               desc2->other_reg = desc1->other_reg;
+               flags |= regs->ternary ? VALUE_INPUT : VALUE_OUTPUT;
+               if(regs->descs[0].used || regs->descs[0].live)
+               {
+                       flags |= VALUE_USED;
+               }
+       }
+       if(value == regs->descs[1].value)
+       {
+               flags |= VALUE_INPUT;
+               if(regs->descs[1].used || regs->descs[1].live)
+               {
+                       flags |= VALUE_USED;
+               }
+       }
+       if(value == regs->descs[2].value)
+       {
+               flags |= VALUE_INPUT;
+               if(regs->descs[2].used || regs->descs[2].live)
+               {
+                       flags |= VALUE_USED;
+               }
        }
+       return flags;
 }
 
 /*
- * Assign value to the register it is already in if possible. This is the case
- * if the register is not already assigned to and one of the following is true:
- *  1. The value is output and it the only value in register.
- *  2. The value is input and it is not clobbered.
- *  3. The value is input and it the only value in register, it is clobbered
- *     but not used afterwards.
- *  4. The value is input and it is clobbered even if we do not use its
- *     register. This might be because the instruction clobbers all or
- *     some registers (see _jit_regs_clobber_all(), jit_regs_clobber()).
- * NOTE: In the last case it might be possible to find a not clobbered register
- * where the value could be moved to so that the original copy can be used for
- * input without spilling. However probaly this corner case is not worth the
- * effort.
+ * Check if two values are known to be equal.
  */
-static void
-reuse_register(jit_gencode_t gen, _jit_regs_t *regs, _jit_regdesc_t *desc, int 
output)
+static int
+are_values_equal(_jit_regdesc_t *desc1, _jit_regdesc_t *desc2)
 {
-       int reg;
-       int other_reg;
-
-       reg = -1;
-       other_reg = -1;
-       if(desc->value->in_register)
+       if(desc1->value && desc2->value)
        {
-               reg = desc->value->reg;
-
-               if(_jit_regs_needs_long_pair(desc->value->type))
+               if(desc1->value == desc2->value)
                {
-                       other_reg = _jit_reg_info[reg].other_reg;
+                       return 1;
                }
-               else
+               if(desc1->value->in_register && desc2->value->in_register)
                {
-                       other_reg = -1;
+                       return desc1->value->reg == desc2->value->reg;
                }
        }
-       else if(desc->value->in_global_register
-               && (regs->is_ternary
-                   || desc->value == regs->descs[0].value
-                   || desc->value != regs->descs[1].value))
-       {
-               /* It is safe to use the global register directly when it
-                  is not a binary operation which output value is going
-                  to override the original one. */
-               reg = desc->value->global_reg;
-               other_reg = -1;
+       return 0;
+}
+
+static int
+output_clobbers_register(jit_gencode_t gen, jit_value_t value, int reg)
+{
+       if(value->has_global_register && value->global_reg == reg)
+       {
+               return 0;
+       }
+       if(value->in_register && value->reg == reg && 
gen->contents[reg].num_values == 1)
+       {
+               return 0;
        }
+       return 1;
+}
+
+static int
+value_clobbers_register(jit_gencode_t gen, _jit_regs_t *regs, int index, int 
reg, int other_reg)
+{
+       _jit_regdesc_t *desc;
+       int out_index;
 
-       if(reg < 0)
+       if(index < 0)
        {
-               return;
+               /* scratch register */
+               return 1;
        }
 
-       if(jit_reg_is_used(regs->assigned, reg))
+       desc = &regs->descs[index];
+       if(!desc->value)
        {
-               return;
+               return 0;
+       }
+
+       if(regs->ternary || !regs->descs[0].value)
+       {
+               /* this is either a ternary op or a binary/unary note and
+                  it has only input values */
+               if(regs->on_stack)
+               {
+                       /* pop all input values */
+                       return 1;
+               }
+               return desc->clobber;
+       }
+
+       if(index == 0)
+       {
+               /* output value */
+               return output_clobbers_register(gen, desc->value, reg);
        }
-       if(output)
+       if(index == 1 && !regs->descs[2].value)
+       {
+               /* input of a unary op */
+               return 1;
+       }
+
+       if(regs->on_stack)
        {
-               if(gen->contents[reg].num_values > 1)
+               if(!regs->no_pop)
                {
-                       return;
+                       /* one input register is popped another is cloberred by 
output */
+                       return 1;
                }
+
+               out_index = 1 + (regs->reverse_dest ^ regs->reverse_args);
        }
        else
        {
-               if(desc->clobber
-                  && (desc->live || desc->used || 
gen->contents[reg].num_values > 1)
-                  && !jit_reg_is_used(regs->clobber, reg))
+               out_index = 1;
+       }
+
+       if(index == out_index)
+       {
+               /* the output of a binary op clobbers this input value */
+               return 1;
+       }
+
+       return desc->clobber;
+}
+
+/*
+ * Set assigned and clobbered flags for register.
+ */
+static void
+set_register_bits(jit_gencode_t gen, _jit_regs_t *regs, int index)
+{
+       _jit_regdesc_t *desc;
+       int output, clobber;
+
+       desc = &regs->descs[index];
+       if(desc->reg >= 0)
+       {
+               output = (index == 0 && !regs->ternary);
+               if(output)
+               {
+                       clobber = output_clobbers_register(gen, desc->value, 
desc->reg);
+               }
+               else
+               {
+                       clobber = desc->clobber;
+               }
+
+               jit_reg_set_used(regs->assigned, desc->reg);
+               if(clobber)
+               {
+                       jit_reg_set_used(regs->clobber, desc->reg);
+               }
+               if(desc->other_reg >= 0)
                {
-                       return;
+                       jit_reg_set_used(regs->assigned, desc->other_reg);
+                       if(clobber)
+                       {
+                               jit_reg_set_used(regs->clobber, 
desc->other_reg);
+                       }
                }
        }
+}
 
-       if(other_reg >= 0)
+/*
+ * To avoid circular movements of input values in place of each other
+ * check if the current value overwrites any of the others.
+ */
+static int
+thrashes_register(jit_gencode_t gen, _jit_regs_t *regs,
+                 _jit_regdesc_t *desc, int reg, int other_reg)
+{
+       int reg2, other_reg2;
+       if(regs->ternary && regs->descs[0].value && 
regs->descs[0].value->in_register
+          && !(desc && are_values_equal(&regs->descs[0], desc)))
+       {
+               reg2 = regs->descs[0].value->reg;
+               if(reg2 == reg || reg2 == other_reg)
+               {
+                       return 1;
+               }
+               if(gen->contents[reg2].is_long_start)
+               {
+                       other_reg2 = OTHER_REG(reg2);
+                       if(other_reg2 == reg /*|| other_reg2 == other_reg*/)
+                       {
+                               return 1;
+                       }
+               }
+       }
+       if(regs->descs[1].value && regs->descs[1].value->in_register
+          && !(desc && are_values_equal(&regs->descs[1], desc)))
+       {
+               reg2 = regs->descs[1].value->reg;
+               if(reg2 == reg || reg2 == other_reg)
+               {
+                       return 1;
+               }
+               if(gen->contents[reg2].is_long_start)
+               {
+                       other_reg2 = OTHER_REG(reg2);
+                       if(other_reg2 == reg /*|| other_reg2 == other_reg*/)
+                       {
+                               return 1;
+                       }
+               }
+       }
+       if(regs->descs[2].value && regs->descs[2].value->in_register
+          && !(desc && are_values_equal(&regs->descs[2], desc)))
        {
-               if(jit_reg_is_used(regs->assigned, other_reg))
+               reg2 = regs->descs[2].value->reg;
+               if(reg2 == reg || reg2 == other_reg)
+               {
+                       return 1;
+               }
+               if(gen->contents[reg2].is_long_start)
                {
-                       return;
+                       other_reg2 = OTHER_REG(reg2);
+                       if(other_reg2 == reg /*|| other_reg2 == other_reg*/)
+                       {
+                               return 1;
+                       }
                }
+       }
+       return 0;
+}
 
-               if(output)
+static int
+compute_spill_cost(jit_gencode_t gen, _jit_regs_t *regs, int reg, int 
other_reg)
+{
+       int cost, index, usage;
+       jit_value_t value;
+
+       cost = 0;
+       for(index = 0; index < gen->contents[reg].num_values; index++)
+       {
+               value = gen->contents[reg].values[index];
+               if(value->is_constant)
+               {
+                       continue;
+               }
+               usage = value_usage(regs, value);
+               if((usage & VALUE_OUTPUT) != 0)
+               {
+                       continue;
+               }
+               if((usage & VALUE_INPUT) != 0 && (usage & VALUE_USED) == 0)
+               {
+                       continue;
+               }
+               if(value->has_global_register)
                {
-                       if(gen->contents[other_reg].num_values > 1)
+                       if(!value->in_global_register)
                        {
-                               return;
+                               cost += 1;
                        }
                }
                else
                {
-                       if(desc->clobber
-                          && (desc->live || desc->used || 
gen->contents[other_reg].num_values > 1)
-                          && !jit_reg_is_used(regs->clobber, other_reg))
+                       if(!value->in_frame)
                        {
-                               return;
+                               cost += 10;
                        }
                }
        }
-
-       desc->reg = reg;
-       desc->other_reg = other_reg;
-       set_register_bits(regs, desc, output);
+       if(other_reg >= 0)
+       {
+               for(index = 0; index < gen->contents[other_reg].num_values; 
index++)
+               {
+                       value = gen->contents[other_reg].values[index];
+                       if(value->is_constant)
+                       {
+                               continue;
+                       }
+                       usage = value_usage(regs, value);
+                       if((usage & VALUE_OUTPUT) != 0)
+                       {
+                               continue;
+                       }
+                       if((usage & VALUE_INPUT) != 0 && (usage & VALUE_USED) 
== 0)
+                       {
+                               continue;
+                       }
+                       if(value->has_global_register)
+                       {
+                               if(!value->in_global_register)
+                               {
+                                       cost += 1;
+                               }
+                       }
+                       else
+                       {
+                               if(!value->in_frame)
+                               {
+                                       cost += 10;
+                               }
+                       }
+               }
+       }
+       return cost;
 }
 
+/* TODO: update comments */
+/*
+ * Assign value to the register it is already in if possible. This is the case
+ * if the register is not already assigned to and one of the following is true:
+ *  1. The value is output and it the only value in register.
+ *  2. The value is input and it is not clobbered.
+ *  3. The value is input and it the only value in register, it is clobbered
+ *     but not used afterwards.
+ *  4. The value is input and it is clobbered even if we do not use its
+ *     register. This might be because the instruction clobbers all or
+ *     some registers (see _jit_regs_clobber_all(), jit_regs_clobber()).
+ * NOTE: In the last case it might be possible to find a not clobbered register
+ * where the value could be moved to so that the original copy can be used for
+ * input without spilling. However probaly this corner case is not worth the
+ * effort.
+ */
 /*
  * Assign value to a register that is cheapest to use. We are here either
  * because the value is not in register or it is but the register will be
@@ -1855,436 +2067,946 @@
  *
  */
 static int
-use_cheapest_register(jit_gencode_t gen, _jit_regs_t *regs, _jit_regdesc_t 
*desc, int output)
+use_cheapest_register(jit_gencode_t gen, _jit_regs_t *regs, int index)
 {
+       _jit_regdesc_t *desc;
+       int output;
        int type;
        int need_pair;
-       int reg;
-       int other_reg;
-       int cost;
-       int free_reg;
+       int reg, other_reg;
        int suitable_reg;
        int suitable_cost;
        int suitable_age;
-       int index;
+       int cost;
 
-       if(desc)
+       if(index >= 0)
        {
+               desc = &regs->descs[index];
+               if(!desc->value)
+               {
+                       return -1;
+               }
+               output = (index == 0 && !regs->ternary);
+               need_pair = _jit_regs_needs_long_pair(desc->value->type);
                type = get_register_type(desc->value, need_pair);
                if(!type)
                {
                        return -1;
                }
+       }
+       else
+       {
+               desc = 0;
+               output = 0;
+               need_pair = 0;
+               type = JIT_REG_WORD;
+       }
+
+       suitable_reg = -1;
+       suitable_cost = COST_TOO_MUCH;
+       suitable_age = -1;
+       for(reg = 0; reg < JIT_NUM_REGS; reg++)
+       {
+               if((_jit_reg_info[reg].flags & type) == 0)
+               {
+                       continue;
+               }
+
+               if(need_pair)
+               {
+                       other_reg = OTHER_REG(reg);
+               }
+               else
+               {
+                       other_reg = -1;
+               }
+
+               if(jit_reg_is_used(gen->inhibit, reg)
+                  || jit_reg_is_used(regs->assigned, reg))
+               {
+                       continue;
+               }
+               if(other_reg >= 0)
+               {
+                       if(jit_reg_is_used(gen->inhibit, other_reg)
+                          || jit_reg_is_used(regs->assigned, other_reg))
+                       {
+                               continue;
+                       }
+               }
+
+               if(jit_reg_is_used(gen->permanent, reg))
+               {
+                       /* We can use a global register only if it is the 
register
+                          that contains the value itself and it is not 
clobbered. */
+                       if(desc
+                          && desc->value->has_global_register
+                          && desc->value->global_reg == reg
+                          && !value_clobbers_register(gen, regs, index, reg, 
other_reg))
+                       {
+                               if(output || desc->value->in_global_register)
+                               {
+                                       cost = 0;
+                               }
+                               else
+                               {
+                                       cost = 1;
+                               }
+                       }
+                       else
+                       {
+                               cost = COST_TOO_MUCH;
+                       }
+               }
+               else if(thrashes_register(gen, regs, desc, reg, other_reg))
+               {
+                       cost = COST_TOO_MUCH;
+               }
+               else if(desc && desc->value->in_register)
+               {
+                       if(reg == desc->value->reg)
+                       {
+                               if(value_clobbers_register(gen, regs, index, 
reg, other_reg)
+                                  && !(jit_reg_is_used(regs->clobber, reg)
+                                       || (other_reg >= 0
+                                           && jit_reg_is_used(regs->clobber, 
other_reg))))
+                               {
+                                       cost = compute_spill_cost(gen, regs, 
reg, other_reg);
+                               }
+                               else
+                               {
+                                       cost = 0;
+                               }
+                       }
+                       else
+                       {
+                               cost = 1 + compute_spill_cost(gen, regs, reg, 
other_reg);
+                       }
+               }
+               else
+               {
+                       cost = 10 + compute_spill_cost(gen, regs, reg, 
other_reg);
+               }
+
+               if(cost < suitable_cost
+                  || (cost == suitable_cost && gen->contents[reg].age < 
suitable_age))
+               {
+                       /* This is the oldest suitable register of this type */
+                       suitable_reg = reg;
+                       suitable_cost = cost;
+                       suitable_age = gen->contents[reg].age;
+               }
+       }
+
+       reg = suitable_reg;
+       if(desc && reg >= 0)
+       {
+               if(need_pair)
+               {
+                       other_reg = OTHER_REG(reg);
+               }
+               else
+               {
+                       other_reg = -1;
+               }
+
+               desc->reg = reg;
+               desc->other_reg = other_reg;
+               set_register_bits(gen, regs, index);
+       }
+
+       return reg;
+}
+
+/*
+ * Assign diplicate input value to the same register if possible.
+ * The first value has to be already assigned. The second value
+ * is assigned to the same register if it is equal to the first
+ * and neither of them is clobbered.
+ */
+static void
+check_duplicate_value(_jit_regs_t *regs, _jit_regdesc_t *desc1, _jit_regdesc_t 
*desc2)
+{
+       if((!regs->on_stack || regs->x87_arith)
+          && are_values_equal(desc1, desc2)
+          && desc1->reg >= 0 && desc2->reg < 0
+          && !desc1->early_clobber && !desc2->early_clobber)
+       {
+               desc2->reg = desc1->reg;
+               desc2->other_reg = desc1->other_reg;
+               desc2->on_stack = desc1->on_stack;
+               desc2->duplicate = 1;
+       }
+}
+
+/*
+ * 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.
+ */
+static void
+select_order(jit_gencode_t gen, _jit_regs_t *regs)
+{
+       _jit_regdesc_t *desc0;
+       _jit_regdesc_t *desc1;
+       _jit_regdesc_t *desc2;
+       _jit_regdesc_t temp_desc;
+       int keep1, keep2;
+       int out_index;
+
+       if(regs->ternary || !(regs->commutative || regs->x87_arith))
+       {
+               /* Bail out on ternary or non-commutative and non-x87 
instruction. */
+               return;
+       }
+
+       desc0 = &regs->descs[0];
+       desc1 = &regs->descs[1];
+       desc2 = &regs->descs[2];
+
+       if(!desc0->value || !desc1->value || !desc2->value)
+       {
+               /* Bail out on binary notes or unary ops. */
+               return;
+       }
+
+       /* Determine if we might want to keep either of input values
+          in registers after the operation completion. */
+       if(regs->clobber_all)
+       {
+               keep1 = 0;
+               keep2 = 0;
+       }
+       else
+       {
+               keep1 = desc1->used && (desc1->value != desc0->value) && 
!desc1->clobber;
+               keep2 = desc2->used && (desc2->value != desc0->value) && 
!desc2->clobber;
+       }
+
+       /* Choose between pop and no-pop instructions. */
+       if(regs->on_stack)
+       {
+               regs->no_pop = (regs->x87_arith && (keep1 || keep2));
+       }
+       else
+       {
+               regs->no_pop = 0;
+       }
+
+       /* Choose the input value to be clobbered by output. */
+       if(regs->on_stack ? regs->no_pop : regs->commutative)
+       {
+               if(keep1 && keep2)
+               {
+                       /* TODO: take into account that value might by copied to
+                          another register */
+                       if(desc1->value->in_register)
+                       {
+                               if(desc2->value->in_register)
+                               {
+                                       /* TODO: compare spill cost and live 
ranges  */
+                                       out_index = 1;
+                               }
+                               else
+                               {
+                                       /* TODO: compare spill cost and live 
ranges  */
+                                       out_index = 2;
+                               }
+                       }
+                       else
+                       {
+                               if(desc2->value->in_register)
+                               {
+                                       /* TODO: compare spill cost and live 
ranges  */
+                                       out_index = 1;
+                               }
+                               else
+                               {
+                                       /* TODO: use live ranges  */
+                                       out_index = 1;
+                               }
+                       }
+               }
+               else if(keep1)
+               {
+                       out_index = 2;
+               }
+               else if(keep2)
+               {
+                       out_index = 1;
+               }
+               else
+               {
+                       if(!(desc1->used || desc1->live))
+                       {
+                               out_index = 1;
+                       }
+                       else if(!(desc2->used || desc2->live))
+                       {
+                               out_index = 2;
+                       }
+                       else
+                       {
+                               out_index = 1;
+                       }
+               }
+
+               if(out_index == 2)
+               {
+                       if(regs->on_stack)
+                       {
+                               regs->reverse_dest = 1;
+                       }
+                       else if(regs->commutative)
+                       {
+                               temp_desc = *desc1;
+                               *desc1 = *desc2;
+                               *desc2 = temp_desc;
+                       }
+               }
+       }
+
+       return;
+}
+
+static void
+select_stack_order(jit_gencode_t gen, _jit_regs_t *regs)
+{
+       _jit_regdesc_t *desc1;
+       _jit_regdesc_t *desc2;
+       _jit_regdesc_t temp_desc;
+       int top_index;
+
+       /* Choose instruction that results into fewer exchanges. */
+       if(regs->on_stack && regs->no_pop && (regs->commutative || 
regs->reversible))
+       {
+               desc1 = &regs->descs[1];
+               desc2 = &regs->descs[2];
+
+               if(desc1->value->in_register && desc2->value->in_register)
+               {
+                       /* TODO: simulate spills and find out if any of the 
input
+                          values ends up on the stack top. */
+                       /* TODO: otherwise see if the next instruction wants 
output
+                          or remaining input to be on the stack top. */
+                       top_index = 2;
+               }
+               else if(desc1->value->in_register)
+               {
+                       top_index = 2;
+               }
+               else if(desc2->value->in_register)
+               {
+                       top_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)
+                       {
+                               regs->reverse_args = 1;
+                       }
+                       else /*if(regs->commutative)*/
+                       {
+                               temp_desc = *desc1;
+                               *desc1 = *desc2;
+                               *desc2 = temp_desc;
+                       }
+                       regs->reverse_dest ^= 1;
+               }
+       }
+}
+
+static void
+bind_value(jit_gencode_t gen, jit_value_t value, int reg, int other_reg, int 
still_in_frame)
+{
+       int stack_start;
+
+       if(value->has_global_register && value->global_reg == reg)
+       {
+               value->in_register = 0;
+               value->in_global_register = 1;
+               return;
+       }
+
+       gen->contents[reg].values[0] = value;
+       gen->contents[reg].num_values = 1;
+       gen->contents[reg].age = gen->current_age;
+       gen->contents[reg].used_for_temp = 0;
+       gen->contents[reg].is_long_end = 0;
+       if(other_reg == -1)
+       {
+               gen->contents[reg].is_long_start = 0;
+       }
+       else
+       {
+               gen->contents[reg].is_long_start = 1;
+               gen->contents[other_reg].num_values = 0;
+               gen->contents[other_reg].age = gen->current_age;
+               gen->contents[other_reg].used_for_temp = 0;
+               gen->contents[other_reg].is_long_start = 0;
+               gen->contents[other_reg].is_long_end = 1;
+       }
+       ++(gen->current_age);
+
+       /* Set the stack mappings for this register */
+       if(IS_STACK_REG(reg))
+       {
+               stack_start = get_stack_start(reg);
+               gen->contents[reg].remap = stack_start;
+               gen->stack_map[stack_start] = reg;
+       }
+
+       /* Adjust the value to reflect that it is in "reg", and maybe the frame 
*/
+       value->in_register = 1;
+       if(value->has_global_register)
+       {
+               value->in_global_register = still_in_frame;
+       }
+       else
+       {
+               value->in_frame = still_in_frame;
+       }
+       value->reg = reg;
+}
+
+/*
+ * Disassociate value with register.
+ */
+static void
+unbind_value(jit_gencode_t gen, jit_value_t value, int reg, int other_reg)
+{
+       int index;
+
+       if(!value->in_register || value->reg != reg)
+       {
+               return;
+       }
+
+       value->in_register = 0;
+       value->reg = -1;
+
+       for(index = gen->contents[reg].num_values - 1; index >= 0; --index)
+       {
+               if(gen->contents[reg].values[index] == value)
+               {
+                       --(gen->contents[reg].num_values);
+                       for(; index < gen->contents[reg].num_values; index++)
+                       {
+                               gen->contents[reg].values[index] = 
gen->contents[reg].values[index + 1];
+                       }
+                       break;
+               }
+       }
+
+       if(gen->contents[reg].num_values == 0)
+       {
+               gen->contents[reg].remap = -1;
+               if(other_reg >= 0)
+               {
+                       gen->contents[reg].is_long_start = 0;
+                       gen->contents[other_reg].is_long_end = 0;
+               }
+       }
+}
+
+/*
+ * Swap the contents of a register and the top of the register stack. If
+ * the register is not a stack register then the function has no effect.
+ */
+static void
+exch_stack_top(jit_gencode_t gen, int reg, int pop)
+{
+       int top;
+       int index;
+       int num_values;
+       jit_value_t value1;
+       jit_value_t value2;
+
+       if(!IS_STACK_REG(reg))
+       {
+               return;
+       }
+
+       /* Find the top of the stack. */
+       top = gen->stack_map[get_stack_start(reg)];
+
+       /* Generate exchange instruction. */
+       _jit_gen_exch_top(gen, reg, pop);
+
+       /* Update information about the contents of the registers.  */
+       for(index = 0;
+           index < gen->contents[reg].num_values && index < 
gen->contents[top].num_values;
+           index++)
+       {
+               value1 = (index < gen->contents[reg].num_values
+                         ? gen->contents[reg].values[index] : 0);
+               value2 = (index < gen->contents[top].num_values
+                         ? gen->contents[top].values[index] : 0);
+
+               if(pop)
+               {
+                       if(value1)
+                       {
+                               value1->reg = -1;
+                       }
+                       gen->contents[top].values[index] = 0;
+               }
+               else
+               {
+                       if(value1)
+                       {
+                               value1->reg = top;
+                       }
+                       gen->contents[top].values[index] = value1;
+               }
+               if(value2)
+               {
+                       value2->reg = reg;
+               }
+               gen->contents[reg].values[index] = value2;
+       }
+       num_values = gen->contents[top].num_values;
+       if(pop)
+       {
+               gen->contents[top].num_values = 0;
+       }
+       else
+       {
+               gen->contents[top].num_values = gen->contents[reg].num_values;
+       }
+       gen->contents[reg].num_values = num_values;
+}
+
+/*
+ * Spill the top of the register stack.
+ */
+static void
+spill_stack_top(jit_gencode_t gen, _jit_regs_t *regs, int reg)
+{
+       int top, index;
+       jit_value_t value;
+       int usage, value_used;
 
-               need_pair = _jit_regs_needs_long_pair(desc->value->type);
-       }
-       else
+       if(!IS_STACK_REG(reg))
        {
-               type = JIT_REG_WORD;
-               need_pair = 0;
+               return;
        }
 
-       free_reg = -1;
-       suitable_reg = -1;
-       suitable_cost = 0;
-       suitable_age = -1;
-       for(reg = 0; reg < JIT_NUM_REGS; ++reg)
+       /* Find the top of the stack. */
+       reg = get_stack_start(reg);
+       top = gen->stack_map[reg];
+
+       value_used = 0;
+       for(index = gen->contents[reg].num_values - 1; index >= 0; --index)
        {
-               if((_jit_reg_info[reg].flags & type) == 0)
+               value = gen->contents[reg].values[index];
+
+               usage = value_usage(regs, value);
+               if((usage & VALUE_INPUT) != 0 && (usage & VALUE_USED) == 0)
                {
                        continue;
                }
 
-               if((_jit_reg_info[reg].flags & JIT_REG_IN_STACK) != 0)
+               if(!(value->is_constant || value->in_frame || (usage & 
VALUE_OUTPUT) != 0))
                {
-                       /* TODO: Support stack registers. */
-                       return -1;
-               }
+                       if((usage & VALUE_INPUT) == 0 && 
gen->contents[top].num_values == 1)
+                       {
+                               value_used = 1;
+                       }
 
-               if(need_pair)
-               {
-                       other_reg = _jit_reg_info[reg].other_reg;
-               }
-               else
-               {
-                       other_reg = -1;
+                       _jit_gen_spill_top(gen, top, value, value_used);
+                       value->in_frame = 1;
                }
 
-               if(jit_reg_is_used(gen->permanent, reg)
-                  || jit_reg_is_used(gen->inhibit, reg)
-                  || jit_reg_is_used(regs->assigned, reg))
+               if((usage & VALUE_INPUT) == 0)
                {
-                       continue;
+                       unbind_value(gen, value, top, -1);
+                       if(gen->contents[top].num_values == 0)
+                       {
+                               _jit_gen_free_reg(gen, top, -1, value_used);
+
+                               /* Shift everything after this register up by 
one position */
+                               while(gen->stack_map[reg] != -1)
+                               {
+                                       if(IS_STACK_END(reg))
+                                       {
+                                               gen->stack_map[reg] = -1;
+                                               break;
+                                       }
+                                       gen->contents[gen->stack_map[reg + 
1]].remap = reg;
+                                       gen->stack_map[reg] = 
gen->stack_map[reg + 1];
+                                       ++reg;
+                               }
+                       }
                }
-               if(other_reg >= 0)
+       }
+}
+
+/*
+ * Spill regualar (non-stack) register.
+ */
+static void
+spill_reg(jit_gencode_t gen, _jit_regs_t *regs, int reg)
+{
+       int other_reg, index, usage;
+       jit_value_t value;
+
+       /* Find the other register in a long pair */
+       if(gen->contents[reg].is_long_start)
+       {
+               other_reg = OTHER_REG(reg);
+       }
+       else if(gen->contents[reg].is_long_end)
+       {
+               other_reg = reg;
+               for(reg = 0; reg < JIT_NUM_REGS; ++reg)
                {
-                       if(jit_reg_is_used(gen->permanent, other_reg)
-                          || jit_reg_is_used(gen->inhibit, other_reg)
-                          || jit_reg_is_used(regs->assigned, other_reg))
+                       if(other_reg == OTHER_REG(reg))
                        {
-                               continue;
+                               break;
                        }
                }
+       }
+       else
+       {
+               other_reg = -1;
+       }
 
-               if(gen->contents[reg].num_values == 0
-                  && !gen->contents[reg].is_long_end
-                  && (other_reg < 0 || gen->contents[other_reg].num_values == 
0))
+       for(index = gen->contents[reg].num_values - 1; index >= 0; --index)
+       {
+               value = gen->contents[reg].values[index];
+
+               usage = value_usage(regs, value);
+               if((usage & VALUE_INPUT) != 0 && (usage & VALUE_USED) == 0)
                {
-                       free_reg = reg;
-                       break;
+                       continue;
                }
 
-               cost = 0;
-               for(index = 0; index < gen->contents[reg].num_values; index++)
+               if((usage & VALUE_OUTPUT) == 0)
                {
-                       
if(gen->contents[reg].values[index]->has_global_register)
+                       if(value->has_global_register)
                        {
-                               
if(!gen->contents[reg].values[index]->in_global_register)
+                               if(!value->in_global_register)
                                {
-                                       cost += 1;
+                                       _jit_gen_spill_reg(gen, reg, other_reg, 
value);
+                                       value->in_global_register = 1;
                                }
                        }
                        else
                        {
-                               if(!gen->contents[reg].values[index]->in_frame)
-                               {
-                                       cost += 3;
-                               }
-                       }
-               }
-               if(other_reg >= 0)
-               {
-                       for(index = 0; index < 
gen->contents[other_reg].num_values; index++)
-                       {
-                               
if(gen->contents[other_reg].values[index]->has_global_register)
-                               {
-                                       
if(!gen->contents[other_reg].values[index]->in_global_register)
-                                       {
-                                               cost += 1;
-                                       }
-                               }
-                               else
+                               if(!(value->is_constant || value->in_frame))
                                {
-                                       
if(!gen->contents[other_reg].values[index]->in_frame)
-                                       {
-                                               cost += 3;
-                                       }
+                                       _jit_gen_spill_reg(gen, reg, other_reg, 
value);
+                                       value->in_frame = 1;
                                }
                        }
                }
 
-               if(suitable_reg == -1
-                  || cost < suitable_cost
-                  || (cost == suitable_cost && gen->contents[reg].age < 
suitable_age))
+               if((usage & VALUE_INPUT) == 0)
                {
-                       /* This is the oldest suitable register of this type */
-                       suitable_reg = reg;
-                       suitable_cost = cost;
-                       suitable_age = gen->contents[reg].age;
+                       unbind_value(gen, value, reg, other_reg);
                }
        }
+}
 
-       if(desc && desc->value->in_register && free_reg < 0)
-       {
-               /* Case 2. */
-               reg = desc->value->reg;
-       }
-       else if(free_reg >= 0)
+static void
+spill_value(jit_gencode_t gen, jit_value_t value, int reg, int other_reg)
+{
+       if(IS_STACK_REG(reg))
        {
-               /* Cases 1 and 3. */
-               reg = free_reg;
        }
        else
        {
-               /* Case 4. */
-               reg = suitable_reg;
-       }
-
-       if(desc && reg >= 0)
-       {
-               if(need_pair)
+               if(value->has_global_register)
                {
-                       other_reg = _jit_reg_info[reg].other_reg;
+                       if(value->global_reg != reg && 
!value->in_global_register)
+                       {
+                               _jit_gen_spill_reg(gen, reg, other_reg, value);
+                               value->in_global_register = 1;
+                       }
                }
                else
                {
-                       other_reg = -1;
+                       if(!value->in_frame)
+                       {
+                               _jit_gen_spill_reg(gen, reg, other_reg, value);
+                               value->in_frame = 1;
+                       }
                }
-
-               desc->reg = reg;
-               desc->other_reg = other_reg;
-               set_register_bits(regs, desc, output);
        }
-
-       return reg;
 }
 
 static void
-set_register(jit_gencode_t gen, _jit_regdesc_t *desc, int still_in_frame)
+adjust_assignment(jit_gencode_t gen, _jit_regs_t *regs, int index)
 {
-       int reg, other_reg;
-       int first_stack_reg;
-
-       reg = desc->reg;
-       other_reg = desc->other_reg;
+       _jit_regdesc_t *desc;
 
-       if(desc->value->has_global_register && desc->value->global_reg == reg)
+       desc = &regs->descs[index];
+       if(!desc->value || !desc->on_stack)
        {
-               desc->value->in_register = 0;
-               desc->value->in_global_register = 1;
                return;
        }
 
-       gen->contents[reg].values[0] = desc->value;
-       gen->contents[reg].num_values = 1;
-       gen->contents[reg].age = gen->current_age;
-       gen->contents[reg].used_for_temp = 0;
-       gen->contents[reg].is_long_end = 0;
-       if(other_reg == -1)
-       {
-               gen->contents[reg].is_long_start = 0;
-       }
-       else
+       if(desc->reg >= (regs->stack_start + regs->initial_stack_size))
        {
-               gen->contents[reg].is_long_start = 1;
-               gen->contents[other_reg].num_values = 0;
-               gen->contents[other_reg].age = gen->current_age;
-               gen->contents[other_reg].used_for_temp = 0;
-               gen->contents[other_reg].is_long_start = 0;
-               gen->contents[other_reg].is_long_end = 1;
+               desc->reg -= regs->initial_stack_size;
+               desc->reg += regs->current_stack_size;
+               return;
        }
 
-       /* Set the stack mappings for this register */
-       if((_jit_reg_info[reg].flags & JIT_REG_IN_STACK) != 0)
+       for(index = 0; index < regs->num_exchanges; index++)
        {
-               first_stack_reg = reg;
-               while((_jit_reg_info[first_stack_reg].flags & 
JIT_REG_START_STACK) == 0)
+               if(desc->reg == regs->exchanges[index][0])
                {
-                       --first_stack_reg;
+                       desc->reg = regs->exchanges[index][1];
+               }
+               else if(desc->reg == regs->exchanges[index][1])
+               {
+                       desc->reg = regs->exchanges[index][0];
                }
-               gen->contents[reg].remap = first_stack_reg;
-               gen->stack_map[first_stack_reg] = desc->reg;
        }
-
-       /* Adjust the value to reflect that it is in "reg", and maybe the frame 
*/
-       desc->value->in_register = 1;
-       if(desc->value->has_global_register)
-               desc->value->in_global_register = still_in_frame;
-       else
-               desc->value->in_frame = still_in_frame;
-       desc->value->reg = reg;
 }
 
 static void
-load_single(jit_gencode_t gen, _jit_regdesc_t *desc)
+load_input_value(jit_gencode_t gen, _jit_regs_t *regs, int index)
 {
-       if(!desc->value)
+       int reg, other_reg;
+       _jit_regdesc_t *desc;
+
+       desc = &regs->descs[index];
+       if(!desc->value || desc->duplicate)
        {
                return;
        }
 
        if(desc->value->in_register)
        {
-               if(desc->value->reg != desc->reg)
+               reg = desc->value->reg;
+               if(reg != desc->reg)
                {
-                       if(gen->contents[desc->reg].num_values > 0)
+                       _jit_gen_load_value(gen, desc->reg, desc->other_reg, 
desc->value);
+                       if(gen->contents[reg].is_long_start)
                        {
-                               spill_register(gen, desc->reg);
+                               other_reg = OTHER_REG(reg);
                        }
-                       if(desc->other_reg >= 0 && 
gen->contents[desc->other_reg].num_values > 0)
+                       else
                        {
-                               spill_register(gen, desc->other_reg);
+                               other_reg = -1;
                        }
-                       _jit_gen_load_value(gen, desc->reg, desc->other_reg, 
desc->value);
+                       spill_value(gen, desc->value, reg, other_reg);
+                       unbind_value(gen, desc->value, reg, other_reg);
+                       bind_value(gen, desc->value, desc->reg, 
desc->other_reg, 1);
+               }
+               else
+               {
+                       gen->contents[desc->value->reg].age = gen->current_age;
+                       if(desc->other_reg >= 0)
+                       {
+                               gen->contents[OTHER_REG(desc->value->reg)].age 
= gen->current_age;
+                       }
+                       ++(gen->current_age);
                }
        }
        else if(desc->value->in_global_register)
        {
                if(desc->value->global_reg != desc->reg)
                {
-                       if(gen->contents[desc->reg].num_values > 0)
-                       {
-                               spill_register(gen, desc->reg);
-                       }
-                       if(desc->other_reg >= 0 && 
gen->contents[desc->other_reg].num_values > 0)
-                       {
-                               spill_register(gen, desc->other_reg);
-                       }
                        _jit_gen_load_value(gen, desc->reg, desc->other_reg, 
desc->value);
-                       set_register(gen, desc, 1);
+                       bind_value(gen, desc->value, desc->reg, 
desc->other_reg, 1);
                }
        }
        else
        {
-               if(gen->contents[desc->reg].num_values > 0)
-               {
-                       spill_register(gen, desc->reg);
-               }
-               if(desc->other_reg >= 0 && 
gen->contents[desc->other_reg].num_values > 0)
-               {
-                       spill_register(gen, desc->other_reg);
-               }
                _jit_gen_load_value(gen, desc->reg, desc->other_reg, 
desc->value);
-               set_register(gen, desc, 1);
+               bind_value(gen, desc->value, desc->reg, desc->other_reg, 1);
+       }
+
+       jit_reg_set_used(gen->touched, desc->reg);
+       if(desc->other_reg >= 0)
+       {
+               jit_reg_set_used(gen->touched, desc->reg);
        }
 }
 
 static void
-load_couple(jit_gencode_t gen, _jit_regdesc_t *desc1, _jit_regdesc_t *desc2)
+move_input_value(jit_gencode_t gen, _jit_regs_t *regs, int index)
 {
-       int reg2, other_reg2;
+       _jit_regdesc_t *desc;
+       int reg, top;
 
-       if(!desc1->value || !desc1->value->in_register || desc1->value->reg == 
desc1->reg)
+       desc = &regs->descs[index];
+       if(!desc->value || desc->duplicate || !desc->value->in_register)
        {
-               load_single(gen, desc2);
-               load_single(gen, desc1);
+               return;
+       }
+
+       top = regs->stack_start + regs->current_stack_size - 1;
+
+       if(desc->reg < (regs->stack_start + regs->current_stack_size))
+       {
+               reg = desc->reg;
        }
-       else if(!desc2->value || !desc2->value->in_register || 
desc2->value->reg == desc2->reg)
+       else if(regs->ternary && index == 2
+               && regs->descs[0].value && regs->descs[1].value
+               && !regs->descs[0].value->in_register && 
regs->descs[1].value->in_register)
        {
-               load_single(gen, desc1);
-               load_single(gen, desc2);
+               reg = top - 1;
        }
        else
        {
-               reg2 = desc2->value->reg;
-               if(gen->contents[reg2].is_long_start)
-               {
-                       other_reg2 = _jit_reg_info[reg2].other_reg;
-               }
-               else
-               {
-                       other_reg2 = -1;
-               }
+               reg = top;
+       }
 
-               if(desc1->reg != reg2 && desc1->other_reg != reg2
-                  && (other_reg2 < 0
-                      || (desc1->reg != other_reg2 && desc1->other_reg != 
other_reg2)))
+       if(desc->value->reg != reg)
+       {
+               if(desc->value->reg != top)
                {
-                       load_single(gen, desc1);
-                       load_single(gen, desc2);
+                       exch_stack_top(gen, desc->value->reg, 0);
                }
-               else
+               if(reg != top)
                {
-                       load_single(gen, desc2);
-                       load_single(gen, desc1);
+                       exch_stack_top(gen, reg, 0);
                }
        }
 }
 
 static void
-load_triple(jit_gencode_t gen, _jit_regdesc_t *desc1, _jit_regdesc_t *desc2, 
_jit_regdesc_t *desc3)
+commit_input_value(jit_gencode_t gen, _jit_regs_t *regs, int index)
 {
-       int reg1, other_reg1;
-       int reg2, other_reg2;
-       int reg3, other_reg3;
+       _jit_regdesc_t *desc;
+       int reg, other_reg;
 
-       if(!desc1->value || !desc1->value->in_register || desc1->value->reg == 
desc1->reg)
+       desc = &regs->descs[index];
+       if(!(desc->value && desc->value->in_register))
        {
-               load_couple(gen, desc2, desc3);
-               load_single(gen, desc1);
+               return;
        }
-       else if(!desc2->value || !desc2->value->in_register || 
desc2->value->reg == desc2->reg)
+
+       reg = desc->value->reg;
+       if(gen->contents[reg].is_long_start)
        {
-               load_couple(gen, desc1, desc3);
-               load_single(gen, desc2);
+               other_reg = OTHER_REG(reg);
        }
-       else if(!desc3->value || !desc3->value->in_register || 
desc3->value->reg == desc3->reg)
+       else
        {
-               load_couple(gen, desc1, desc2);
-               load_single(gen, desc3);
+               other_reg = -1;
        }
-       else
+
+       /* If the value is clobbered then it must have been spilled
+          before the operation. Simply unbind it here. */
+       if(jit_reg_is_used(regs->clobber, reg)
+          || (other_reg >= 0 && jit_reg_is_used(regs->clobber, other_reg)))
        {
-               reg1 = desc1->value->reg;
-               if(gen->contents[reg1].is_long_start)
-               {
-                       other_reg1 = _jit_reg_info[reg1].other_reg;
-               }
-               else
-               {
-                       other_reg1 = -1;
-               }
+               unbind_value(gen, desc->value, reg, other_reg);
+               return;
+       }
 
-               reg2 = desc2->value->reg;
-               if(gen->contents[reg2].is_long_start)
-               {
-                       other_reg2 = _jit_reg_info[reg2].other_reg;
-               }
-               else
+       if(!desc->used)
+       {
+               if(desc->live)
                {
-                       other_reg2 = -1;
+                       spill_value(gen, desc->value, reg, other_reg);
                }
+               unbind_value(gen, desc->value, reg, other_reg);
+       }
+}
 
-               reg3 = desc3->value->reg;
-               if(gen->contents[reg3].is_long_start)
-               {
-                       other_reg3 = _jit_reg_info[reg3].other_reg;
-               }
-               else
-               {
-                       other_reg3 = -1;
-               }
+static void
+commit_output_value(jit_gencode_t gen, _jit_regs_t *regs)
+{
+       _jit_regdesc_t *desc;
 
-               if(desc1->reg != reg2 && desc1->other_reg != reg2
-                  && desc1->reg != reg3 && desc1->other_reg != reg3
-                  && (other_reg2 < 0
-                      || (desc1->reg != other_reg2 && desc1->other_reg != 
other_reg2))
-                  && (other_reg3 < 0
-                      || (desc1->reg != other_reg3 && desc1->other_reg != 
other_reg3)))
-               {
-                       load_single(gen, desc1);
-                       load_couple(gen, desc2, desc3);
-               }
-               else if(desc2->reg != reg1 && desc2->other_reg != reg1
-                       && desc2->reg != reg3 && desc2->other_reg != reg3
-                       && (other_reg1 < 0
-                           || (desc2->reg != other_reg1 && desc2->other_reg != 
other_reg1))
-                       && (other_reg3 < 0
-                           || (desc2->reg != other_reg3 && desc2->other_reg != 
other_reg3)))
-               {
-                       load_single(gen, desc2);
-                       load_couple(gen, desc1, desc3);
-               }
-               else
+       desc = &regs->descs[0];
+       if(!desc->value)
+       {
+               return;
+       }
+
+       if(desc->value->in_register)
+       {
+               unbind_value(gen, desc->value, desc->value->reg, 
OTHER_REG(desc->value->reg));
+       }
+       if(desc->used || desc->live)
+       {
+               bind_value(gen, desc->value, desc->reg, desc->other_reg, 0);
+               if(!desc->used)
                {
-                       load_single(gen, desc3);
-                       load_couple(gen, desc1, desc2);
+                       spill_value(gen, desc->value, desc->reg, 
desc->other_reg);
+                       unbind_value(gen, desc->value, desc->reg, 
desc->other_reg);
                }
        }
+
+       jit_reg_set_used(gen->touched, desc->reg);
+       if(desc->other_reg >= 0)
+       {
+               jit_reg_set_used(gen->touched, desc->other_reg);
+       }
 }
 
 void
-_jit_regs_init(_jit_regs_t *regs, int is_ternary, int is_commutative)
+_jit_regs_init(_jit_regs_t *regs, int flags)
 {
-       int i;
-
-       regs->is_ternary = is_ternary;
-       regs->is_commutative = is_commutative;
+       int index;
 
-       for(i = 0; i < _JIT_REGS_VALUE_MAX; i++)
-       {
-               regs->descs[i].value = 0;
-               regs->descs[i].reg = -1;
-               regs->descs[i].other_reg = -1;
-               regs->descs[i].clobber = 0;
-               regs->descs[i].live = 0;
-               regs->descs[i].used = 0;
+       regs->clobber_all = (flags & _JIT_REGS_CLOBBER_ALL) != 0;
+       regs->ternary = (flags & _JIT_REGS_TERNARY) != 0;
+       regs->branch = (flags & _JIT_REGS_BRANCH) != 0;
+       regs->copy = (flags & _JIT_REGS_COPY) != 0;
+       regs->commutative = (flags & _JIT_REGS_COMMUTATIVE) != 0;
+       regs->on_stack = (flags & _JIT_REGS_STACK) != 0;
+       regs->x87_arith = (flags & _JIT_REGS_X87_ARITH) != 0;
+       regs->reversible = (flags & _JIT_REGS_REVERSIBLE) != 0;
+
+       regs->no_pop = 0;
+       regs->reverse_dest = 0;
+       regs->reverse_args = 0;
+
+       for(index = 0; index < _JIT_REGS_VALUE_MAX; index++)
+       {
+               regs->descs[index].value = 0;
+               regs->descs[index].reg = -1;
+               regs->descs[index].other_reg = -1;
+               regs->descs[index].clobber = 0;
+               regs->descs[index].early_clobber = 0;
+               regs->descs[index].live = 0;
+               regs->descs[index].used = 0;
+               regs->descs[index].on_stack = 0;
+               regs->descs[index].duplicate = 0;
        }
        regs->num_descs = 0;
 
-       for(i = 0; i < _JIT_REGS_SCRATCH_MAX; i++)
+       for(index = 0; index < _JIT_REGS_SCRATCH_MAX; index++)
        {
-               regs->scratch[1] = -1;
+               regs->scratch[index] = -1;
        }
        regs->num_scratch = 0;
 
        regs->assigned = jit_regused_init;
        regs->clobber = jit_regused_init;
+
+       regs->stack_start = -1;
+       regs->stack_count = 0;
+       regs->initial_stack_size = 0;
+       regs->current_stack_size = 0;
 }
 
 void
-_jit_regs_set_dest(_jit_regs_t *regs, jit_insn_t insn, int clobber, int reg, 
int other_reg)
+_jit_regs_set_dest(_jit_regs_t *regs, jit_insn_t insn, int flags, int reg, int 
other_reg)
 {
+       if((insn->flags & JIT_INSN_DEST_OTHER_FLAGS) != 0)
+       {
+               return;
+       }
+
        if(regs->num_descs < 1)
        {
                regs->num_descs = 1;
@@ -2296,9 +3018,17 @@
                regs->descs[0].reg = reg;
                regs->descs[0].other_reg = other_reg;
        }
-       if(!regs->is_ternary || clobber)
+       if(regs->ternary)
        {
-               regs->descs[0].clobber = 1;
+               if((flags & _JIT_REGS_EARLY_CLOBBER) != 0)
+               {
+                       regs->descs[0].clobber = 1;
+                       regs->descs[0].early_clobber = 1;
+               }
+               else if((flags & _JIT_REGS_CLOBBER) != 0)
+               {
+                       regs->descs[0].clobber = 1;
+               }
        }
        if((insn->flags & JIT_INSN_DEST_LIVE) != 0)
        {
@@ -2308,11 +3038,20 @@
        {
                regs->descs[0].used = 1;
        }
+       if(regs->on_stack)
+       {
+               regs->descs[0].on_stack = 1;
+       }
 }
 
 void
-_jit_regs_set_value1(_jit_regs_t *regs, jit_insn_t insn, int clobber, int reg, 
int other_reg)
+_jit_regs_set_value1(_jit_regs_t *regs, jit_insn_t insn, int flags, int reg, 
int other_reg)
 {
+       if((insn->flags & JIT_INSN_VALUE1_OTHER_FLAGS) != 0)
+       {
+               return;
+       }
+
        if(regs->num_descs < 2)
        {
                regs->num_descs = 2;
@@ -2324,7 +3063,12 @@
                regs->descs[1].reg = reg;
                regs->descs[1].other_reg = other_reg;
        }
-       if(clobber)
+       if((flags & _JIT_REGS_EARLY_CLOBBER) != 0)
+       {
+               regs->descs[1].clobber = 1;
+               regs->descs[1].early_clobber = 1;
+       }
+       else if((flags & _JIT_REGS_CLOBBER) != 0)
        {
                regs->descs[1].clobber = 1;
        }
@@ -2336,11 +3080,20 @@
        {
                regs->descs[1].used = 1;
        }
+       if(regs->on_stack)
+       {
+               regs->descs[1].on_stack = 1;
+       }
 }
 
 void
-_jit_regs_set_value2(_jit_regs_t *regs, jit_insn_t insn, int clobber, int reg, 
int other_reg)
+_jit_regs_set_value2(_jit_regs_t *regs, jit_insn_t insn, int flags, int reg, 
int other_reg)
 {
+       if((insn->flags & JIT_INSN_VALUE2_OTHER_FLAGS) != 0)
+       {
+               return;
+       }
+
        if(regs->num_descs < 3)
        {
                regs->num_descs = 3;
@@ -2352,7 +3105,12 @@
                regs->descs[2].reg = reg;
                regs->descs[2].other_reg = other_reg;
        }
-       if(clobber)
+       if((flags & _JIT_REGS_EARLY_CLOBBER) != 0)
+       {
+               regs->descs[2].clobber = 1;
+               regs->descs[2].early_clobber = 1;
+       }
+       else if((flags & _JIT_REGS_CLOBBER) != 0)
        {
                regs->descs[2].clobber = 1;
        }
@@ -2364,6 +3122,10 @@
        {
                regs->descs[2].used = 1;
        }
+       if(regs->on_stack)
+       {
+               regs->descs[2].on_stack = 1;
+       }
 }
 
 void
@@ -2376,100 +3138,53 @@
 }
 
 void
-_jit_regs_clobber(_jit_regs_t *regs, int reg)
+_jit_regs_set_clobber(_jit_regs_t *regs, int reg)
 {
        jit_reg_set_used(regs->clobber, reg);
 }
 
-void
-_jit_regs_clobber_all(_jit_regs_t *regs)
-{
-       regs->clobber = jit_regused_init_used;
-}
-
 int
 _jit_regs_dest(_jit_regs_t *regs)
 {
-       int reg;
-       reg = regs->descs[0].reg;
-       if(reg >= 0)
-       {
-               return _jit_reg_info[reg].cpu_reg;
-       }
-       return -1;
+       return regs->descs[0].reg;
 }
 
 int
 _jit_regs_value1(_jit_regs_t *regs)
 {
-       int reg;
-       reg = regs->descs[1].reg;
-       if(reg >= 0)
-       {
-               return _jit_reg_info[reg].cpu_reg;
-       }
-       return -1;
+       return regs->descs[1].reg;
 }
 
 int
 _jit_regs_value2(_jit_regs_t *regs)
 {
-       int reg;
-       reg = regs->descs[2].reg;
-       if(reg >= 0)
-       {
-               return _jit_reg_info[reg].cpu_reg;
-       }
-       return -1;
+       return regs->descs[2].reg;
 }
 
 int
 _jit_regs_dest_other(_jit_regs_t *regs)
 {
-       int reg;
-       reg = regs->descs[0].other_reg;
-       if(reg >= 0)
-       {
-               return _jit_reg_info[reg].cpu_reg;
-       }
-       return -1;
+       return regs->descs[0].other_reg;
 }
 
 int
 _jit_regs_value1_other(_jit_regs_t *regs)
 {
-       int reg;
-       reg = regs->descs[1].other_reg;
-       if(reg >= 0)
-       {
-               return _jit_reg_info[reg].cpu_reg;
-       }
-       return -1;
+       return regs->descs[1].other_reg;
 }
 
 int
 _jit_regs_value2_other(_jit_regs_t *regs)
 {
-       int reg;
-       reg = regs->descs[2].other_reg;
-       if(reg >= 0)
-       {
-               return _jit_reg_info[reg].cpu_reg;
-       }
-       return -1;
+       return regs->descs[2].other_reg;
 }
 
 int
 _jit_regs_scratch(_jit_regs_t *regs, int index)
 {
-       int reg;
        if(index < regs->num_scratch && index >= 0)
        {
-               reg = regs->scratch[index];
-               if(reg >= 0)
-               {
-                       return _jit_reg_info[reg].cpu_reg;
-               }
+               return regs->scratch[index];
        }
        return -1;
 }
@@ -2477,197 +3192,155 @@
 int
 _jit_regs_assign(jit_gencode_t gen, _jit_regs_t *regs)
 {
-       _jit_regdesc_t *desc1;
-       _jit_regdesc_t *desc2;
-       _jit_regdesc_t *desc3;
-       _jit_regdesc_t tmp;
-       int index;
+       int index, out_index;
 
-       desc1 = &regs->descs[0];
-       desc2 = &regs->descs[1];
-       desc3 = &regs->descs[2];
+       /* Process pre-assigned registers. */
 
-       /* If the operation is not ternary its output clobbers the first input 
value. */
-       if(!regs->is_ternary && desc1->value && desc2->value)
+       if(regs->descs[0].reg >= 0)
        {
-               /* If the operation is commutative choose which value is 
cheaper to clobber. */
-               if(regs->is_commutative && desc3->value)
-               {
-                       if((desc2->value != desc1->value && desc3->value == 
desc1->value)
-                          || (desc2->live && !desc3->live && !desc2->used && 
!desc3->used)
-                          || (desc2->used && !desc3->used)
-                          || (!desc2->value->in_frame && 
desc3->value->in_frame))
-                       {
-                               tmp = *desc2;
-                               *desc2 = *desc3;
-                               *desc3 = tmp;
-                       }
-               }
-
-               if(desc1->value != desc2->value)
+               if(IS_STACK_REG(regs->descs[0].reg))
                {
-                       desc2->clobber = 1;
+                       return 0;
                }
+               set_register_bits(gen, regs, 0);
        }
-
-       /* Process pre-assigned registers. */
-
-       if(desc1->reg >= 0)
+       if(regs->descs[1].reg >= 0)
        {
-               if(regs->is_ternary)
-               {
-                       set_register_bits(regs, desc1, 0);
-               }
-               else
+               if(IS_STACK_REG(regs->descs[1].reg))
                {
-                       set_register_bits(regs, desc1, 1);
+                       return 0;
                }
+               set_register_bits(gen, regs, 1);
        }
-       if(desc2->reg >= 0)
-       {
-               set_register_bits(regs, desc2, 0);
-       }
-       if(desc3->reg >= 0)
+       if(regs->descs[2].reg >= 0)
        {
-               set_register_bits(regs, desc3, 0);
+               if(IS_STACK_REG(regs->descs[2].reg))
+               {
+                       return 0;
+               }
+               set_register_bits(gen, regs, 2);
        }
 
        for(index = 0; index < regs->num_scratch; index++)
        {
                if(regs->scratch[index] >= 0)
                {
+                       if(IS_STACK_REG(regs->scratch[index]))
+                       {
+                               return 0;
+                       }
                        jit_reg_set_used(regs->assigned, regs->scratch[index]);
                        jit_reg_set_used(regs->clobber, regs->scratch[index]);
                }
        }
 
-       /* For values that are already in registers try to keep them there. */
-
-       if(!regs->is_ternary && desc1->value && desc2->value)
+       if(regs->clobber_all)
        {
-               if(desc1->reg < 0 && desc2->reg < 0)
+               for(index = 0; index < JIT_NUM_REGS; index++)
                {
-                       /* If input value is in register and it will not be
-                          used again we can save one move by placing output
-                          value into that register. */
-                       if(!(desc2->live || desc2->used))
-                       {
-                               reuse_register(gen, regs, desc2, 0);
-                               if(desc2->reg >= 0)
-                               {
-                                       desc1->reg = desc2->reg;
-                                       desc1->other_reg = desc2->other_reg;
-                                       set_register_bits(regs, desc1, 1);
-                               }
-                       }
-                       if(desc1->reg < 0)
+                       if((_jit_reg_info[index].flags & JIT_REG_FIXED)
+                          || jit_reg_is_used(gen->permanent, index))
                        {
-                               reuse_register(gen, regs, desc1, 1);
-                               if(desc1->reg >= 0)
-                               {
-                                       desc2->reg = desc1->reg;
-                                       desc2->other_reg = desc1->other_reg;
-                                       set_register_bits(regs, desc2, 0);
-                               }
+                               continue;
                        }
+                       jit_reg_set_used(regs->clobber, index);
                }
        }
-       else
-       {
-               if(desc1->value && desc1->reg < 0)
-               {
-                       reuse_register(gen, regs, desc1, 0);
-               }
-               if(desc2->value && desc2->reg < 0)
-               {
-                       reuse_register(gen, regs, desc2, 0);
-               }
-       }
-       if(desc3->value && desc3->reg < 0)
-       {
-               reuse_register(gen, regs, desc3, 0);
-       }
+
+       select_order(gen, regs);
+       out_index = 1 + (regs->reverse_dest ^ regs->reverse_args);
 
        /* Assign the remaining registers. */
 
-       if(regs->is_ternary)
+       if(regs->ternary)
        {
-               if(desc1->value && desc1->reg < 0)
-               {
-                       use_cheapest_register(gen, regs, desc1, 0);
-                       if(desc1->reg < 0)
-                       {
-                               return 0;
-                       }
-               }
-
-               reuse_duplicate_value(desc1, desc2);
-               reuse_duplicate_value(desc1, desc3);
-
-               if(desc2->value && desc2->reg < 0)
+               if(regs->descs[0].value && regs->descs[0].reg < 0)
                {
-                       use_cheapest_register(gen, regs, desc2, 0);
-                       if(desc2->reg < 0)
+                       use_cheapest_register(gen, regs, 0);
+                       if(regs->descs[0].reg < 0)
                        {
                                return 0;
                        }
                }
+               check_duplicate_value(regs, &regs->descs[0], &regs->descs[1]);
+               check_duplicate_value(regs, &regs->descs[0], &regs->descs[2]);
        }
-       else
+       else if(regs->descs[0].value && regs->descs[out_index].value)
        {
-               if(desc1->value && desc1->reg < 0)
+               if(regs->descs[0].reg < 0 && regs->descs[out_index].reg < 0)
                {
-                       if(desc2->reg >= 0)
-                       {
-                               desc1->reg = desc2->reg;
-                               desc1->other_reg = desc2->other_reg;
-                               set_register_bits(regs, desc1, 1);
-                       }
-                       else
+                       if(regs->descs[out_index].value->in_register
+                          && 
gen->contents[regs->descs[out_index].value->reg].num_values == 1
+                          && !(regs->descs[out_index].live || 
regs->descs[out_index].used))
                        {
-                               use_cheapest_register(gen, regs, desc1, 1);
-                               if(desc1->reg < 0)
+                               use_cheapest_register(gen, regs, out_index);
+                               if(regs->descs[out_index].reg < 0)
                                {
                                        return 0;
                                }
                        }
-               }
-
-               if(desc2->value && desc2->reg < 0)
-               {
-                       if(desc1->reg >= 0)
-                       {
-                               desc2->reg = desc1->reg;
-                               desc2->other_reg = desc1->other_reg;
-                               set_register_bits(regs, desc2, 0);
-                       }
-                       else
+                       else if(regs->descs[0].value->has_global_register
+                               || (regs->descs[0].value->in_register
+                                   && 
gen->contents[regs->descs[0].value->reg].num_values == 1))
                        {
-                               use_cheapest_register(gen, regs, desc2, 0);
-                               if(desc2->reg < 0)
+                               use_cheapest_register(gen, regs, 0);
+                               if(regs->descs[0].reg < 0)
                                {
                                        return 0;
                                }
                        }
                }
+               if(regs->descs[0].reg >= 0)
+               {
+                       regs->descs[out_index].reg = regs->descs[0].reg;
+                       regs->descs[out_index].other_reg = 
regs->descs[0].other_reg;
+                       set_register_bits(gen, regs, out_index);
+               }
        }
-
-       reuse_duplicate_value(desc2, desc3);
-
-       if(desc3->value && desc3->reg < 0)
+       if(regs->descs[1].value && regs->descs[1].reg < 0)
+       {
+               use_cheapest_register(gen, regs, 1);
+               if(regs->descs[1].reg < 0)
+               {
+                       return 0;
+               }
+       }
+       check_duplicate_value(regs, &regs->descs[1], &regs->descs[2]);
+       if(regs->descs[2].value && regs->descs[2].reg < 0)
        {
-               use_cheapest_register(gen, regs, desc3, 0);
-               if(desc3->reg < 0)
+               use_cheapest_register(gen, regs, 2);
+               if(regs->descs[2].reg < 0)
                {
                        return 0;
                }
        }
+       if(regs->descs[0].value && regs->descs[0].reg < 0)
+       {
+               if(regs->descs[out_index].reg < 0)
+               {
+                       use_cheapest_register(gen, regs, 0);
+                       if(regs->descs[0].reg < 0)
+                       {
+                               return 0;
+                       }
+               }
+               else
+               {
+                       regs->descs[0].reg = regs->descs[out_index].reg;
+                       regs->descs[0].other_reg = 
regs->descs[out_index].other_reg;
+                       set_register_bits(gen, regs, 0);
+               }
+       }
 
        for(index = 0; index < regs->num_scratch; index++)
        {
                if(regs->scratch[index] < 0)
                {
-                       regs->scratch[index] = use_cheapest_register(gen, regs, 
0, 0);
+                       regs->scratch[index] = use_cheapest_register(gen, regs, 
-1);
+                       if(regs->scratch[index] < 0)
+                       {
+                               return 0;
+                       }
                        jit_reg_set_used(regs->assigned, regs->scratch[index]);
                        jit_reg_set_used(regs->clobber, regs->scratch[index]);
                }
@@ -2679,109 +3352,262 @@
 int
 _jit_regs_gen(jit_gencode_t gen, _jit_regs_t *regs)
 {
-       _jit_regdesc_t *desc1;
-       _jit_regdesc_t *desc2;
-       _jit_regdesc_t *desc3;
-       int reg;
-
-       desc1 = &regs->descs[0];
-       desc2 = &regs->descs[1];
-       desc3 = &regs->descs[2];
+       int reg, stack_start, top;
 
-       /* Load values. */
-       if(regs->is_ternary)
+       /* Collect information about stack registers. */
+       if(regs->descs[0].on_stack)
        {
-               load_triple(gen, desc1, desc2, desc3);
+               regs->stack_start = get_stack_start(regs->descs[0].reg);
+               if(regs->ternary)
+               {
+                       ++(regs->stack_count);
+               }
        }
-       else
+       if(regs->descs[1].on_stack && !regs->descs[1].duplicate)
+       {
+               stack_start = get_stack_start(regs->descs[1].reg);
+               if(regs->stack_start < 0)
+               {
+                       regs->stack_start = stack_start;
+               }
+               else if(stack_start != regs->stack_start)
+               {
+                       return 0;
+               }
+               ++(regs->stack_count);
+       }
+       if(regs->descs[2].on_stack && !regs->descs[2].duplicate)
+       {
+               stack_start = get_stack_start(regs->descs[2].reg);
+               if(regs->stack_start < 0)
+               {
+                       regs->stack_start = stack_start;
+               }
+               else if(stack_start != regs->stack_start)
+               {
+                       return 0;
+               }
+               ++(regs->stack_count);
+       }
+       if(regs->stack_count > 0)
+       {
+               regs->initial_stack_size = get_stack_size(gen, 
regs->stack_start);
+       }
+
+       /* Spill clobbered registers. */
+       stack_start = 0;
+       for(reg = 0; reg < JIT_NUM_REGS; reg++)
        {
-               if(desc1->value)
+               if((_jit_reg_info[reg].flags & JIT_REG_FIXED))
+               {
+                       continue;
+               }
+
+               /* Remember this register if it is the start of a stack */
+               if(IS_STACK_START(reg))
+               {
+                       stack_start = reg;
+               }
+
+               if(!jit_reg_is_used(regs->clobber, reg))
+               {
+                       continue;
+               }
+               if(jit_reg_is_used(gen->permanent, reg))
                {
-                       /* To avoid spilling the value that we are about to
-                          change pretend that its current content is already
-                          in the frame. The correct flags will be set by the
-                          _jit_regs_commit() function. */
-                       if(desc1->value->has_global_register)
+                       /* Oops, global register. */
+                       if(regs->branch)
                        {
-                               desc1->value->in_global_register = 1;
+                               /* After the branch is taken there is no way
+                                  to load global register back. */
+                               return 0;
                        }
-                       else
+                       _jit_gen_spill_global(gen, reg, 
gen->contents[reg].values[0]);
+                       continue;
+               }
+
+               /* If this is a stack register, then we need to find the
+                  register that contains the top-most stack position,
+                  because we must spill stack registers from top down.
+                  As we spill each one, something else will become the top */
+               if(IS_STACK_REG(reg))
+               {
+                       top = gen->stack_map[stack_start];
+                       while(top > reg && jit_reg_is_used(regs->clobber, top))
+                       {
+                               spill_stack_top(gen, regs, stack_start);
+                               if(gen->contents[top].num_values > 0)
+                               {
+                                       /* If one of the input values is on the 
top
+                                          spill_stack_top() does not pop it. */
+                                       break;
+                               }
+                               top = gen->stack_map[stack_start];
+                       }
+                       if(top > reg)
                        {
-                               desc1->value->in_frame = 1;
+                               exch_stack_top(gen, reg, 0);
+                               if(regs->num_exchanges >= 
_JIT_REGS_MAX_EXCHANGES)
+                               {
+                                       return 0;
+                               }
+                               regs->exchanges[regs->num_exchanges][0] = top;
+                               regs->exchanges[regs->num_exchanges][1] = reg;
+                               ++(regs->num_exchanges);
+
+                               if(jit_reg_is_used(regs->clobber, top))
+                               {
+                                       jit_reg_set_used(regs->clobber, reg);
+                               }
+                               else
+                               {
+                                       jit_reg_clear_used(regs->clobber, reg);
+                               }
+                               jit_reg_set_used(regs->clobber, top);
                        }
+                       spill_stack_top(gen, regs, stack_start);
+               }
+               else
+               {
+                       spill_reg(gen, regs, reg);
+               }
+       }
+
+       /* Adjust assignment of stack registers. */
+       if(regs->stack_count > 0)
+       {
+               regs->current_stack_size = get_stack_size(gen, 
regs->stack_start);
+               if(regs->ternary)
+               {
+                       adjust_assignment(gen, regs, 0);
                }
+               adjust_assignment(gen, regs, 1);
+               adjust_assignment(gen, regs, 2);
 
-               load_couple(gen, desc2, desc3);
+               select_stack_order(gen, regs);
        }
 
-       /* Spill clobbered registers. */
-       for(reg = 0; reg < JIT_NUM_REGS; reg++)
+       /* Load values. */
+       if(regs->on_stack)
        {
-               if(jit_reg_is_used(regs->clobber, reg))
+               /* shuffle values that are already on the stack */
+               if(regs->ternary)
                {
-                       if(jit_reg_is_used(gen->permanent, reg))
+                       if(regs->descs[0].value && 
regs->descs[0].value->in_register)
                        {
-                               /* Oops, global register. */
-                               _jit_gen_spill_global(gen, 
gen->contents[reg].values[0]);
+                               move_input_value(gen, regs, 0);
+                               move_input_value(gen, regs, 1);
+                               move_input_value(gen, regs, 2);
                        }
                        else
                        {
-                               spill_register(gen, reg);
+                               move_input_value(gen, regs, 2);
+                               move_input_value(gen, regs, 1);
+                       }
+               }
+               else if(!regs->x87_arith)
+               {
+                       move_input_value(gen, regs, 1);
+                       move_input_value(gen, regs, 2);
+               }
+
+               /* load and shuffle the remaining values */
+               if(regs->x87_arith && regs->reverse_args)
+               {
+                       load_input_value(gen, regs, 2);
+                       move_input_value(gen, regs, 2);
+                       load_input_value(gen, regs, 1);
+                       move_input_value(gen, regs, 1);
+               }
+               else
+               {
+                       if(regs->ternary)
+                       {
+                               load_input_value(gen, regs, 0);
+                               move_input_value(gen, regs, 0);
                        }
+                       load_input_value(gen, regs, 1);
+                       move_input_value(gen, regs, 1);
+                       load_input_value(gen, regs, 2);
+                       move_input_value(gen, regs, 2);
+               }
+       }
+       else
+       {
+               if(regs->ternary)
+               {
+                       load_input_value(gen, regs, 0);
                }
+               load_input_value(gen, regs, 1);
+               load_input_value(gen, regs, 2);
        }
 
        return 1;
 }
 
+int
+_jit_regs_select(_jit_regs_t *regs)
+{
+       int flags;
+
+       flags = 0;
+       if(regs->no_pop)
+       {
+               flags |= _JIT_REGS_NO_POP;
+       }
+       if(regs->reverse_dest)
+       {
+               flags |= _JIT_REGS_REVERSE_DEST;
+       }
+       if(regs->reverse_args)
+       {
+               flags |= _JIT_REGS_REVERSE_ARGS;
+       }
+
+       return flags;
+}
+
 void
 _jit_regs_commit(jit_gencode_t gen, _jit_regs_t *regs)
 {
-       _jit_regdesc_t *desc1;
        int reg;
 
-       desc1 = &regs->descs[0];
-
-       /* If the output register is used in this basic block remember it.
-          Otherwise spill it. */
-       if(!regs->is_ternary && desc1->value)
+       if(regs->ternary)
        {
-               if(desc1->used)
-               {
-                       set_register(gen, desc1, 0);
-               }
-               else
-               {
-                       if(desc1->value->has_global_register)
-                       {
-                               if(desc1->value->global_reg != desc1->reg)
-                               {
-                                       _jit_gen_spill_reg(gen, desc1->reg, 
desc1->other_reg, desc1->value);
-                               }
-                               desc1->value->in_register = 0;
-                               desc1->value->in_global_register = 1;
-                       }
-                       else
-                       {
-                               _jit_gen_spill_reg(gen, desc1->reg, 
desc1->other_reg, desc1->value);
-                               desc1->value->in_register = 0;
-                               desc1->value->in_frame = 1;
-                       }
-               }
+               commit_input_value(gen, regs, 0);
+               commit_input_value(gen, regs, 1);
+               commit_input_value(gen, regs, 2);
+       }
+       else
+       {
+               commit_input_value(gen, regs, 1);
+               commit_input_value(gen, regs, 2);
+               commit_output_value(gen, regs);
+       }
 
-               jit_reg_clear_used(regs->clobber, desc1->reg);
-               if(desc1->other_reg >= 0)
+       /* Load clobbered global registers. */
+       for(reg = JIT_NUM_REGS - 1; reg >= 0; reg--)
+       {
+               if(jit_reg_is_used(regs->clobber, reg) && 
jit_reg_is_used(gen->permanent, reg))
                {
-                       jit_reg_clear_used(regs->clobber, desc1->other_reg);
+                       _jit_gen_load_global(gen, reg, 
gen->contents[reg].values[0]);
                }
        }
+}
 
-       /* Load clobbered global registers. */
-       for(reg = 0; reg < JIT_NUM_REGS; reg++)
+int
+_jit_regs_lookup(char *name)
+{
+       int reg;
+       if(name)
        {
-               if(jit_reg_is_used(regs->clobber, reg) && 
jit_reg_is_used(gen->permanent, reg))
+               for(reg = 0; reg < JIT_NUM_REGS; reg++)
                {
-                       _jit_gen_load_global(gen, gen->contents[reg].values[0]);
+                       if(strcmp(_jit_reg_info[reg].name, name) == 0)
+                       {
+                               return reg;
+                       }
                }
        }
+       return -1;
 }
Index: libjit/jit/jit-reg-alloc.h
diff -u libjit/jit/jit-reg-alloc.h:1.7 libjit/jit/jit-reg-alloc.h:1.8
--- libjit/jit/jit-reg-alloc.h:1.7      Sat Feb 18 19:58:10 2006
+++ libjit/jit/jit-reg-alloc.h  Fri Apr 14 11:46:05 2006
@@ -72,7 +72,44 @@
 /*
  * The maximum number of temporaries per instruction.
  */
-#define _JIT_REGS_SCRATCH_MAX          4
+#define _JIT_REGS_SCRATCH_MAX          6
+
+/*
+ * The maximum number of stack register exchanges.
+ */
+#define _JIT_REGS_MAX_EXCHANGES                16
+
+/*
+ * Flags for _jit_regs_init().
+ */
+#define _JIT_REGS_CLOBBER_ALL          0x0001
+#define _JIT_REGS_TERNARY              0x0002
+#define _JIT_REGS_BRANCH               0x0004
+#define _JIT_REGS_COPY                 0x0008
+#define _JIT_REGS_STACK                        0x0010
+#define _JIT_REGS_X87_ARITH            0x0020
+#define _JIT_REGS_COMMUTATIVE          0x0040
+#define _JIT_REGS_REVERSIBLE           0x0080
+
+/*
+ * Flags for _jit_regs_set_dest(), _jit_regs_set_value1(), 
_jit_regs_set_value2().
+ */
+#define _JIT_REGS_CLOBBER              0x0001
+#define _JIT_REGS_EARLY_CLOBBER                0x0002
+
+/*
+ * 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
+
+/*
+ * This value is used internally to assign a stack register.
+ * It indicates that we are going to use the next free stack
+ * regsiter but we do not yet know which one it is.
+#define _JIT_REGS_NEXT_STACK_REG       0x7fff
+ */
 
 /*
  * Contains register assignment data for single operand.
@@ -80,11 +117,14 @@
 typedef struct
 {
        jit_value_t     value;
-       short           reg;
-       short           other_reg;
-       unsigned        clobber : 1;
+       int             reg;
+       int             other_reg;
        unsigned        live : 1;
        unsigned        used : 1;
+       unsigned        clobber : 1;
+       unsigned        early_clobber : 1;
+       unsigned        on_stack : 1;
+       unsigned        duplicate : 1;
 
 } _jit_regdesc_t;
 
@@ -93,8 +133,18 @@
  */
 typedef struct
 {
-       int             is_ternary;
-       int             is_commutative;
+       unsigned        clobber_all : 1;
+       unsigned        ternary : 1;
+       unsigned        branch : 1;
+       unsigned        copy : 1;
+       unsigned        commutative : 1;
+       unsigned        on_stack : 1;
+       unsigned        x87_arith : 1;
+       unsigned        reversible : 1;
+
+       unsigned        no_pop : 1;
+       unsigned        reverse_dest : 1;
+       unsigned        reverse_args : 1;
 
        _jit_regdesc_t  descs[_JIT_REGS_VALUE_MAX];
        int             num_descs;
@@ -105,17 +155,23 @@
        jit_regused_t   assigned;
        jit_regused_t   clobber;
 
+       int             stack_start;
+       int             stack_count;
+       int             initial_stack_size;
+       int             current_stack_size;
+       int             exchanges[_JIT_REGS_MAX_EXCHANGES][2];
+       int             num_exchanges;
 } _jit_regs_t;
 
-void _jit_regs_init(_jit_regs_t *regs, int is_ternary, int is_commutative);
-void _jit_regs_set_dest(_jit_regs_t *regs, jit_insn_t insn, int clobber, int 
reg, int other_reg);
-void _jit_regs_set_value1(_jit_regs_t *regs, jit_insn_t insn, int clobber, int 
reg, int other_reg);
-void _jit_regs_set_value2(_jit_regs_t *regs, jit_insn_t insn, int clobber, int 
reg, int other_reg);
+void _jit_regs_init(_jit_regs_t *regs, int flags);
+void _jit_regs_set_dest(_jit_regs_t *regs, jit_insn_t insn, int flags, int 
reg, int other_reg);
+void _jit_regs_set_value1(_jit_regs_t *regs, jit_insn_t insn, int flags, int 
reg, int other_reg);
+void _jit_regs_set_value2(_jit_regs_t *regs, jit_insn_t insn, int flags, int 
reg, int other_reg);
 void _jit_regs_set_scratch(_jit_regs_t *regs, int reg);
-void _jit_regs_clobber(_jit_regs_t *regs, int reg);
-void _jit_regs_clobber_all(_jit_regs_t *regs);
+void _jit_regs_set_clobber(_jit_regs_t *regs, int reg);
 int _jit_regs_assign(jit_gencode_t gen, _jit_regs_t *regs);
 int _jit_regs_gen(jit_gencode_t gen, _jit_regs_t *regs);
+int _jit_regs_select(_jit_regs_t *regs);
 void _jit_regs_commit(jit_gencode_t gen, _jit_regs_t *regs);
 int _jit_regs_dest(_jit_regs_t *regs);
 int _jit_regs_value1(_jit_regs_t *regs);
@@ -124,6 +180,7 @@
 int _jit_regs_value1_other(_jit_regs_t *regs);
 int _jit_regs_value2_other(_jit_regs_t *regs);
 int _jit_regs_scratch(_jit_regs_t *regs, int index);
+int _jit_regs_lookup(char *name);
 
 #ifdef __cplusplus
 };




reply via email to

[Prev in Thread] Current Thread [Next in Thread]