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.c jit/jit-re...


From: Aleksey Demakov
Subject: [dotgnu-pnet-commits] libjit ChangeLog jit/jit-reg-alloc.c jit/jit-re...
Date: Thu, 14 Sep 2006 06:27:08 +0000

CVSROOT:        /sources/dotgnu-pnet
Module name:    libjit
Changes by:     Aleksey Demakov <avd>   06/09/14 06:27:08

Modified files:
        .              : ChangeLog 
        jit            : jit-reg-alloc.c jit-reg-alloc.h jit-rules-x86.c 
                         jit-rules-x86.h jit-rules-x86.ins jit-rules.h 

Log message:
        remove "old" register allocator;

CVSWeb URLs:
http://cvs.savannah.gnu.org/viewcvs/libjit/ChangeLog?cvsroot=dotgnu-pnet&r1=1.268&r2=1.269
http://cvs.savannah.gnu.org/viewcvs/libjit/jit/jit-reg-alloc.c?cvsroot=dotgnu-pnet&r1=1.41&r2=1.42
http://cvs.savannah.gnu.org/viewcvs/libjit/jit/jit-reg-alloc.h?cvsroot=dotgnu-pnet&r1=1.18&r2=1.19
http://cvs.savannah.gnu.org/viewcvs/libjit/jit/jit-rules-x86.c?cvsroot=dotgnu-pnet&r1=1.39&r2=1.40
http://cvs.savannah.gnu.org/viewcvs/libjit/jit/jit-rules-x86.h?cvsroot=dotgnu-pnet&r1=1.5&r2=1.6
http://cvs.savannah.gnu.org/viewcvs/libjit/jit/jit-rules-x86.ins?cvsroot=dotgnu-pnet&r1=1.14&r2=1.15
http://cvs.savannah.gnu.org/viewcvs/libjit/jit/jit-rules.h?cvsroot=dotgnu-pnet&r1=1.14&r2=1.15

Patches:
Index: ChangeLog
===================================================================
RCS file: /sources/dotgnu-pnet/libjit/ChangeLog,v
retrieving revision 1.268
retrieving revision 1.269
diff -u -b -r1.268 -r1.269
--- ChangeLog   9 Sep 2006 05:21:03 -0000       1.268
+++ ChangeLog   14 Sep 2006 06:27:08 -0000      1.269
@@ -1,3 +1,14 @@
+2006-09-14  Aleksey Demakov  <address@hidden>
+
+       * jit/jit-reg-alloc.h, jit/jit-reg-alloc.c: remove "old" register
+       allocation code.
+
+       * configure.in: remove --enable-new-reg-alloc option.
+
+       * jit/jit-rules-x86.ins: simplify  JIT_OP_RETURN_LONG rule, lift code
+       from load_small_struct() function to JIT_OP_RETURN_SMALL_STRUCT rule.
+       * jit/jit-rules-x86.c: remove load_small_struct() function.
+
 2006-09-09  Aleksey Demakov  <address@hidden>
 
        * jit/jit-reg-alloc.h, jit/jit-reg-alloc.c:

Index: jit/jit-reg-alloc.c
===================================================================
RCS file: /sources/dotgnu-pnet/libjit/jit/jit-reg-alloc.c,v
retrieving revision 1.41
retrieving revision 1.42
diff -u -b -r1.41 -r1.42
--- jit/jit-reg-alloc.c 9 Sep 2006 05:21:03 -0000       1.41
+++ jit/jit-reg-alloc.c 14 Sep 2006 06:27:08 -0000      1.42
@@ -32,113 +32,71 @@
 
 @*/
 
-/*@
- * @deftypefun void _jit_regs_init_for_block (jit_gencode_t gen)
- * Initialize the register allocation state for a new block.
- * @end deftypefun
address@hidden/
-void _jit_regs_init_for_block(jit_gencode_t gen)
-{
-       int reg;
-       gen->current_age = 1;
-       for(reg = 0; reg < JIT_NUM_REGS; ++reg)
-       {
-               /* Clear everything except permanent and fixed registers */
-               if(!jit_reg_is_used(gen->permanent, reg) &&
-                  (_jit_reg_info[reg].flags & JIT_REG_FIXED) == 0)
-               {
-                       gen->contents[reg].num_values = 0;
-                       gen->contents[reg].is_long_start = 0;
-                       gen->contents[reg].is_long_end = 0;
-                       gen->contents[reg].age = 0;
-                       gen->contents[reg].remap = -1;
-                       gen->contents[reg].used_for_temp = 0;
-               }
-               gen->stack_map[reg] = -1;
-       }
-       gen->inhibit = jit_regused_init;
-}
+/*
+ * Dump debug information about the register allocation state.
+ */
+#undef JIT_REG_DEBUG
 
-/*@
- * @deftypefun int _jit_regs_needs_long_pair (jit_type_t type)
- * Determine if a type requires a long register pair.
- * @end deftypefun
address@hidden/
-int _jit_regs_needs_long_pair(jit_type_t type)
-{
-#if defined(JIT_NATIVE_INT32) && !defined(JIT_BACKEND_INTERP)
-       type = jit_type_normalize(type);
-       if(type)
-       {
-               if(type->kind == JIT_TYPE_LONG || type->kind == JIT_TYPE_ULONG)
-               {
-                       return 1;
-               }
-       }
-       return 0;
+/*
+ * Minimum number of times a candidate must be used before it
+ * is considered worthy of putting in a global register.
+ */
+#define        JIT_MIN_USED            3
+
+/*
+ * Check if the register is on the register stack.
+ */
+#ifdef JIT_REG_STACK
+#define IS_STACK_REG(reg)      ((_jit_reg_info[reg].flags & JIT_REG_IN_STACK) 
!= 0)
 #else
-       /* We don't register pairs on 64-bit platforms or the interpreter */
-       return 0;
+#define IS_STACK_REG(reg)      (0)
 #endif
-}
-
-/*@
- * @deftypefun int _jit_regs_get_cpu (jit_gencode_t gen, int reg, int 
*other_reg)
- * Get the CPU register that corresponds to a pseudo register.
- * "other_reg" will be set to the other register in a pair,
- * or -1 if the register is not part of a pair.
- * @end deftypefun
address@hidden/
-int _jit_regs_get_cpu(jit_gencode_t gen, int reg, int *other_reg)
-{
-       int cpu_reg, other;
-       cpu_reg = gen->contents[reg].remap;
-       if(cpu_reg == -1)
-       {
-               cpu_reg = _jit_reg_info[reg].cpu_reg;
-       }
-       else
-       {
-               cpu_reg = _jit_reg_info[cpu_reg].cpu_reg;
-       }
-       if(gen->contents[reg].is_long_start)
-       {
-               other = _jit_reg_info[reg].other_reg;
-               if(gen->contents[other].remap == -1)
-               {
-                       other = _jit_reg_info[other].cpu_reg;
-               }
-               else
-               {
-                       other = 
_jit_reg_info[gen->contents[other].remap].cpu_reg;
-               }
-       }
-       else
-       {
-               other = -1;
-       }
-       if(other_reg)
-       {
-               *other_reg = other;
-       }
-       return cpu_reg;
-}
 
 /*
- * Dump debug information about the register allocation state.
+ * Get the other register of a long pair.
  */
-/*#define      JIT_REG_DEBUG   1*/
+#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
+
+#define COST_COPY              4
+#define COST_SPILL_DIRTY       16
+#define COST_SPILL_DIRTY_GLOBAL        2
+#define COST_SPILL_CLEAN       1
+#define COST_SPILL_CLEAN_GLOBAL        1
+#define COST_GLOBAL_BIAS       1
+#define COST_THRASH            32
+#define COST_CLOBBER_GLOBAL    1000
+
+#ifdef JIT_BACKEND_X86
+# define ALLOW_CLOBBER_GLOBAL  1
+#else
+# define ALLOW_CLOBBER_GLOBAL  0
+#endif
+
+/* Value usage flags. */
+#define VALUE_INPUT            1
+#define VALUE_USED             2
+#define VALUE_LIVE             4
+#define VALUE_DEAD             8
+
+/* Clobber flags. */
+#define CLOBBER_NONE           0
+#define CLOBBER_INPUT_VALUE    1
+#define CLOBBER_REG            2
+#define CLOBBER_OTHER_REG      4
+
 #ifdef JIT_REG_DEBUG
 static void dump_regs(jit_gencode_t gen, const char *name)
 {
-       int reg;
-       unsigned int index;
+       int reg, index;
+       jit_value_t value;
+
        printf("%s:\n", name);
        for(reg = 0; reg < JIT_NUM_REGS; ++reg)
        {
-               if(gen->contents[reg].num_values == 0 &&
-                  !(gen->contents[reg].used_for_temp) &&
-                  gen->contents[reg].remap == -1)
+               if(gen->contents[reg].num_values == 0 && 
!(gen->contents[reg].used_for_temp))
                {
                        continue;
                }
@@ -147,11 +105,12 @@
                {
                        for(index = 0; index < gen->contents[reg].num_values; 
++index)
                        {
+                               value = gen->contents[reg].values[index];
                                if(index)
+                               {
                                        fputs(", ", stdout);
-                               jit_dump_value(stdout, jit_value_get_function
-                                                                               
(gen->contents[reg].values[index]),
-                                                          
gen->contents[reg].values[index], 0);
+                               }
+                               jit_dump_value(stdout, 
jit_value_get_function(value), value, 0);
                        }
                        if(gen->contents[reg].used_for_temp)
                        {
@@ -166,1873 +125,335 @@
                {
                        printf("free");
                }
-               if(gen->contents[reg].remap != -1)
-               {
-                       printf(", remap=%d", (int)(gen->contents[reg].remap));
-               }
-               for(index = 0; index < JIT_NUM_REGS; ++index)
-               {
-                       if(gen->stack_map[index] == reg)
-                       {
-                               printf(", reverse_remap=%d", (int)index);
-                       }
-               }
                putc('\n', stdout);
        }
 }
 #endif
 
 /*
- * Spill all registers between two end points.
+ * Find the start register of a long pair given the end register.
  */
-static void spill_all_between(jit_gencode_t gen, int first, int last)
+static int
+get_long_pair_start(int other_reg)
 {
-       int reg, posn, other_reg, real_reg;
-       int first_stack_reg = 0;
-       jit_value_t value;
-       int value_used;
-
-#ifdef JIT_REG_DEBUG
-       dump_regs(gen, "enter spill_all_between");
-#endif
-
-       /* Handle the non-stack registers first, as they are easy to spill */
-       for(reg = first; reg <= last; ++reg)
+       int reg;
+       for(reg = 0; reg < JIT_NUM_REGS; reg++)
        {
-               /* Skip this register if it is permanent or fixed */
-               if(jit_reg_is_used(gen->permanent, reg) ||
-                  (_jit_reg_info[reg].flags & JIT_REG_FIXED) != 0)
+               if(other_reg == OTHER_REG(reg))
                {
-                       continue;
+                       return reg;
                }
-
-               /* Remember this register if it is the start of a stack */
-               if((_jit_reg_info[reg].flags & JIT_REG_START_STACK) != 0)
-               {
-                       first_stack_reg = reg;
                }
+       return -1;
+}
 
-               /* 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((_jit_reg_info[reg].flags & JIT_REG_IN_STACK) != 0)
-               {
-                       real_reg = gen->stack_map[first_stack_reg];
-                       if(real_reg == -1)
-                       {
-                               continue;
-                       }
-               }
-               else
+/*
+ * Determine the type of register that we need.
+ */
+static int
+get_register_type(jit_value_t value, int need_pair)
+{
+       switch(jit_type_normalize(value->type)->kind)
                {
-                       real_reg = reg;
-               }
+       case JIT_TYPE_SBYTE:
+       case JIT_TYPE_UBYTE:
+       case JIT_TYPE_SHORT:
+       case JIT_TYPE_USHORT:
+       case JIT_TYPE_INT:
+       case JIT_TYPE_UINT:
+       case JIT_TYPE_NINT:
+       case JIT_TYPE_NUINT:
+       case JIT_TYPE_SIGNATURE:
+       case JIT_TYPE_PTR:
+               return JIT_REG_WORD;
 
-               /* Skip this register if there is nothing in it */
-               if(gen->contents[real_reg].num_values == 0 &&
-                  !(gen->contents[real_reg].used_for_temp))
-               {
-                       continue;
-               }
+       case JIT_TYPE_LONG:
+       case JIT_TYPE_ULONG:
+               return need_pair ? JIT_REG_LONG : JIT_REG_WORD;
 
-               /* Get the other register in a long pair, if there is one */
-               if(gen->contents[real_reg].is_long_start)
-               {
-                       other_reg = _jit_reg_info[real_reg].other_reg;
-               }
-               else
-               {
-                       other_reg = -1;
-               }
+       case JIT_TYPE_FLOAT32:
+               return JIT_REG_FLOAT32;
 
-               /* Spill all values that are associated with the register */
-               value_used = 0;
-               if(gen->contents[real_reg].num_values > 0)
-               {
-                       for(posn = gen->contents[real_reg].num_values - 1;
-                               posn >= 0; --posn)
-                       {
-                               value = gen->contents[real_reg].values[posn];
-                               if(value->has_global_register)
-                               {
-                                       if(!(value->in_global_register))
-                                       {
-                                               _jit_gen_spill_reg(gen, 
real_reg, other_reg, value);
-                                               value->in_global_register = 1;
-                                               value_used = 1;
-                                       }
-                               }
-                               else if(!(value->in_frame))
-                               {
-                                       if((_jit_reg_info[reg].flags & 
JIT_REG_IN_STACK) == 0)
-                                       {
-                                               _jit_gen_spill_reg(gen, 
real_reg, other_reg, value);
-                                       }
-                                       else
-                                       {
-                                               /* The back end needs to think 
that we are spilling
-                                                  the first register in the 
stack, regardless of
-                                                  what "real_reg" might happen 
to be */
-                                               _jit_gen_spill_reg(gen, 
first_stack_reg, -1, value);
-                                       }
-                                       value->in_frame = 1;
-                                       value_used = 1;
-                               }
-                               value->in_register = 0;
-                               value->reg = -1;
-                       }
-               }
+       case JIT_TYPE_FLOAT64:
+               return JIT_REG_FLOAT64;
 
-               /* Free the register */
-               _jit_regs_free_reg(gen, real_reg, value_used);
+       case JIT_TYPE_NFLOAT:
+               return JIT_REG_NFLOAT;
        }
 
-#ifdef JIT_REG_DEBUG
-       dump_regs(gen, "leave spill_all_between");
-#endif
+       return 0;
 }
 
 /*
- * Spill a specific register.  If it is in a stack, then all registers
- * above the specific register must also be spilled.
+ * Check if two values are known to be equal.
  */
-static void spill_register(jit_gencode_t gen, int reg)
+static int
+are_values_equal(_jit_regdesc_t *desc1, _jit_regdesc_t *desc2)
 {
-       if((_jit_reg_info[reg].flags & JIT_REG_IN_STACK) == 0)
-       {
-               spill_all_between(gen, reg, reg);
-       }
-       else
+       if(desc1 && desc2 && desc1->value && desc2->value)
        {
-               int first_reg;
-               reg = gen->contents[reg].remap;
-               first_reg = reg;
-               while((_jit_reg_info[first_reg].flags & JIT_REG_START_STACK) == 
0)
+               if(desc1->value == desc2->value)
                {
-                       --first_reg;
-               }
-               spill_all_between(gen, first_reg, reg);
+                       return 1;
        }
-}
-
-/*
- * Spill all stack registers of a specific type.
- */
-static void spill_all_stack(jit_gencode_t gen, int reg)
-{
-       int first_reg;
-       while((_jit_reg_info[reg].flags & JIT_REG_START_STACK) == 0)
+               if(desc1->value->in_register && desc2->value->in_register)
        {
-               --reg;
+                       return desc1->value->reg == desc2->value->reg;
        }
-       first_reg = reg;
-       while((_jit_reg_info[reg].flags & JIT_REG_END_STACK) == 0)
-       {
-               ++reg;
        }
-       spill_all_between(gen, first_reg, reg);
+       return 0;
 }
 
-/*@
- * @deftypefun void _jit_regs_spill_all (jit_gencode_t gen)
- * Spill all of the temporary registers to memory locations.
- * Normally used at the end of a block, but may also be used in
- * situations where a value must be in a certain register and
- * it is too hard to swap things around to put it there.
- * @end deftypefun
address@hidden/
-void _jit_regs_spill_all(jit_gencode_t gen)
-{
-#ifdef JIT_REG_DEBUG
-       printf("enter _jit_regs_spill_all\n");
-#endif
-
-       spill_all_between(gen, 0, JIT_NUM_REGS - 1);
-
-#ifdef JIT_REG_DEBUG
-       printf("leave _jit_regs_spill_all\n");
-#endif
-}
 
 /*
- * Free a register within a stack, and renumber the other stack registers
- * to compensate for the change.
+ * Get value usage and liveness information. The accurate liveness data is
+ * only available for values used by the current instruction.
+ *
+ * VALUE_INPUT flag is set if the value is one of the instruction's inputs.
+ *
+ * VALUE_LIVE and VALUE_USED flags are set for input values only according
+ * to the liveness flags provided along with the instruction.
+ *
+ * VALUE_DEAD flag is set in two cases. First, it is always set for output
+ * values. Second, it is set for input values that are neither live nor used.
+ *
+ * These flags are used when spilling a register. In this case we generally
+ * do not know if the values in the register are used by the instruction. If
+ * the VALUE_INPUT flag is present then it is so and the value has to be held
+ * in the register for the instruction to succeed. If the VALUE_DEAD flag is
+ * present then there is no need to spill the value and it may be discarded.
+ * Otherwise the value must be spilled.
+ *
+ * The VALUE_LIVE and VALUE_USED flags may only be set for input values of
+ * the instruction. For other values these flags are not set even if they are
+ * perfectly alive. These flags are used as a hint for spill cost calculation.
+ *
+ * NOTE: The output value is considered to be dead because the instruction is
+ * just about to recompute it so there is no point to save it.
+ *
+ * Generally, a value becomes dead just after the instruction that used it
+ * last time. The allocator frees dead values after each instruction so it
+ * might seem that there is no chance to find any dead value on the current
+ * instruction. However if the value is used by the current instruction both
+ * as the input and output then it was alive after the last instruction and
+ * hence was not freed. Also the old allocator might sometimes leave a dead
+ * value in the register and as of this writing the old allocator is still
+ * used by some rules. And just in case if some dead value may creep through
+ * the new allocator...
  */
-static void free_stack_reg(jit_gencode_t gen, int reg)
+static int
+value_usage(_jit_regs_t *regs, jit_value_t value)
 {
-       int remap;
-
-#ifdef JIT_REG_DEBUG
-       dump_regs(gen, "enter free_stack_reg");
-#endif
+       int flags;
 
-       /* Shift everything after this register up by one position */
-       remap = gen->contents[reg].remap;
-       if((_jit_reg_info[remap].flags & JIT_REG_END_STACK) == 0)
+       flags = 0;
+       if(value->is_constant)
+       {
+               flags |= VALUE_DEAD;
+       }
+       if(!regs)
        {
-               ++remap;
-               for(;;)
+               return flags;
+       }
+       if(value == regs->descs[0].value)
+       {
+               if(regs->ternary)
                {
-                       if(gen->stack_map[remap] == -1)
+                       flags |= VALUE_INPUT;
+                       if(regs->descs[0].used)
                        {
-                               /* There are no more active values in this 
stack */
-                               gen->stack_map[remap - 1] = -1;
-                               break;
+                               flags |= VALUE_LIVE | VALUE_USED;
                        }
-                       else if((_jit_reg_info[remap].flags & 
JIT_REG_END_STACK) != 0)
+                       else if(regs->descs[0].live)
                        {
-                               /* This is the last register in the stack */
-                               --(gen->contents[gen->stack_map[remap]].remap);
-                               gen->stack_map[remap - 1] = 
gen->stack_map[remap];
-                               gen->stack_map[remap] = -1;
-                               break;
+                               flags |= VALUE_LIVE;
                        }
                        else
                        {
-                               /* Shift this stack entry up by one */
-                               --(gen->contents[gen->stack_map[remap]].remap);
-                               gen->stack_map[remap - 1] = 
gen->stack_map[remap];
-                               ++remap;
+                               flags |= VALUE_DEAD;
+                       }
                        }
+               else
+               {
+                       flags |= VALUE_DEAD;
                }
        }
-
-       /* Clear the remapping for the register */
-       gen->contents[reg].remap = -1;
-
-#ifdef JIT_REG_DEBUG
-       dump_regs(gen, "leave free_stack_reg");
-#endif
+       if(value == regs->descs[1].value)
+       {
+               flags |= VALUE_INPUT;
+               if(regs->descs[1].used)
+               {
+                       flags |= VALUE_LIVE | VALUE_USED;
+               }
+               else if(regs->descs[1].live)
+               {
+                       flags |= VALUE_LIVE;
+               }
+               else
+               {
+                       flags |= VALUE_DEAD;
+               }
+       }
+       if(value == regs->descs[2].value)
+       {
+               flags |= VALUE_INPUT;
+               if(regs->descs[2].used)
+               {
+                       flags |= VALUE_LIVE | VALUE_USED;
+               }
+               else if(regs->descs[2].live)
+               {
+                       flags |= VALUE_LIVE;
+               }
+               else
+               {
+                       flags |= VALUE_DEAD;
+               }
+       }
+       return flags;
 }
 
 /*
- * Make space for a new stack register in a particular stack.
- * Returns the pseudo register number of the newly allocated register.
+ * Check if the register contains any live values.
  */
-static int create_stack_reg(jit_gencode_t gen, int reg, int roll_down)
+static int
+is_register_alive(jit_gencode_t gen, _jit_regs_t *regs, int reg)
 {
-       int first_stack_reg;
-       int temp_reg, remap;
-
-#ifdef JIT_REG_DEBUG
-       dump_regs(gen, "enter create_stack_reg");
-#endif
+       int index, usage;
 
-       /* Find the first pseudo register in the stack */
-       while((_jit_reg_info[reg].flags & JIT_REG_START_STACK) == 0)
+       if(reg < 0)
        {
-               --reg;
+               return 0;
        }
-       first_stack_reg = reg;
 
-       /* Find a free pseudo register in the stack */
-       for(;;)
-       {
-               if(gen->contents[reg].num_values == 0 &&
-                  !(gen->contents[reg].used_for_temp))
+       /* Assume that a global register is always alive unless it is to be
+          computed right away. */
+       if(jit_reg_is_used(gen->permanent, reg))
                {
-                       break;
-               }
-               if((_jit_reg_info[reg].flags & JIT_REG_END_STACK) != 0)
+               if(!regs->ternary
+                  && regs->descs[0].value
+                  && regs->descs[0].value->has_global_register
+                  && regs->descs[0].value->global_reg == reg)
                {
-                       /* None of the registers are free, so we have to spill 
them all */
-                       spill_all_between(gen, first_stack_reg, reg);
-                       reg = first_stack_reg;
-                       break;
+                       return 0;
                }
-               ++reg;
+               return 1;
        }
 
-       /* Roll the stack remappings down to make room at the top */
-       if(roll_down)
+       if(gen->contents[reg].is_long_end)
        {
-               temp_reg = first_stack_reg - 1;
-               do
+               reg = get_long_pair_start(reg);
+       }
+       for(index = 0; index < gen->contents[reg].num_values; index++)
                {
-                       ++temp_reg;
-                       remap = gen->contents[temp_reg].remap;
-                       if(remap != -1)
+               usage = value_usage(regs, gen->contents[reg].values[index]);
+               if((usage & VALUE_DEAD) == 0)
                        {
-                               /* Change the register's position in the stack 
*/
-                               gen->contents[temp_reg].remap = remap + 1;
-                               gen->stack_map[remap + 1] = temp_reg;
-
-                               /* Mark the rolled-down register position as 
touched */
-                               jit_reg_set_used(gen->touched, remap + 1);
-                       }
+                       return 1;
                }
-               while((_jit_reg_info[temp_reg].flags & JIT_REG_END_STACK) == 0);
-               gen->contents[reg].remap = first_stack_reg;
-               gen->stack_map[first_stack_reg] = reg;
        }
 
-       /* Mark the register as touched, in case it needs to be saved */
-       jit_reg_set_used(gen->touched, reg);
-
-#ifdef JIT_REG_DEBUG
-       dump_regs(gen, "leave create_stack_reg");
-#endif
-
-       /* Return the free register to the caller */
-       return reg;
+       return 0;
 }
 
 /*
- * Free a register, and optionally spill its value.
+ * Determine the effect of using a register for a value. This includes the
+ * following:
+ *  - whether the value is clobbered by the instruction;
+ *  - whether the previous contents of the register is clobbered.
+ *
+ * The value is clobbered by the instruction if it is used as input value
+ * and the output value will go to the same register and these two values
+ * are not equal. Or the instruction has a side effect that destroys the
+ * input value regardless of the output. This is indicated with the
+ * CLOBBER_INPUT_VALUE flag.
+ *
+ * The previous content is clobbered if the register contains any non-dead
+ * values that are destroyed by loading the input value, by computing the
+ * output value, or as a side effect of the instruction.
+ *
+ * The previous content is not clobbered if the register contains only dead
+ * values or it is used for input value that is already in the register so
+ * there is no need to load it and at the same time the instruction has no
+ * side effects that destroy the input value or the register is used for
+ * output value and the only value it contained before is the same value.
+ *
+ * The flag CLOBBER_REG indicates if the previous content of the register is
+ * clobbered. The flag CLOBBER_OTHER_REG indicates that the other register
+ * in a long pair is clobbered.
+ *
  */
-static void free_reg_and_spill
-       (jit_gencode_t gen, int reg, int value_used, int spill)
+static int
+clobbers_register(jit_gencode_t gen, _jit_regs_t *regs, int index, int reg, 
int other_reg)
 {
-       int other_reg, posn;
-       jit_value_t value;
-
-#ifdef JIT_REG_DEBUG
-       dump_regs(gen, "enter free_reg_and_spill");
-#endif
+       int flags;
 
-       /* Find the other register in a long pair */
-       if(gen->contents[reg].is_long_start)
+       if(!regs->descs[index].value)
        {
-               other_reg = _jit_reg_info[reg].other_reg;
-               gen->contents[reg].is_long_start = 0;
-               gen->contents[other_reg].is_long_end = 0;
+               return CLOBBER_NONE;
        }
-       else if(gen->contents[reg].is_long_end)
-       {
-               gen->contents[reg].is_long_end = 0;
-               other_reg = reg;
-               for(reg = 0; reg < JIT_NUM_REGS; ++reg)
+
+       if(regs->ternary || !regs->descs[0].value)
                {
-                       if(other_reg == _jit_reg_info[reg].other_reg)
+               /* this is either a ternary or binary or unary note */
+               if(IS_STACK_REG(reg) || regs->descs[index].clobber)
                        {
-                               gen->contents[reg].is_long_start = 0;
-                               break;
-                       }
-               }
+                       flags = CLOBBER_INPUT_VALUE;
        }
        else
        {
-               other_reg = -1;
+                       flags = CLOBBER_NONE;
        }
-
-       /* Spill the register's contents to the local variable frame */
-       if(spill && gen->contents[reg].num_values > 0)
-       {
-               for(posn = gen->contents[reg].num_values - 1; posn >= 0; --posn)
+       }
+       else if(index == 0)
                {
-                       value = gen->contents[reg].values[posn];
-                       if(value->has_global_register)
+               /* this is the output value of a binary or unary op */
+               flags = CLOBBER_NONE;
+               if(is_register_alive(gen, regs, reg))
                        {
-                               if(!(value->in_global_register))
+                       flags |= CLOBBER_REG;
+               }
+               if(is_register_alive(gen, regs, other_reg))
                                {
-                                       _jit_gen_spill_reg(gen, reg, other_reg, 
value);
-                                       value->in_global_register = 1;
-                                       value_used = 1;
+                       flags |= CLOBBER_OTHER_REG;
                                }
+               return flags;
                        }
-                       else if(!(value->in_frame))
-                       {
-                               if((_jit_reg_info[reg].flags & 
JIT_REG_IN_STACK) == 0)
+       else if(regs->on_stack && !regs->no_pop)
                                {
-                                       _jit_gen_spill_reg(gen, reg, other_reg, 
value);
+               /* this is a binary or unary stack op -- the input value
+                  is either popped or overwritten by the output */
+               flags = CLOBBER_INPUT_VALUE;
                                }
-                               else
+       else if(reg == regs->descs[0].reg
+               || reg == regs->descs[0].other_reg
+               || other_reg == regs->descs[0].reg)
                                {
-                                       _jit_gen_spill_reg
-                                               (gen, gen->contents[reg].remap, 
-1, value);
-                               }
-                               value->in_frame = 1;
-                               value_used = 1;
-                       }
-                       value->in_register = 0;
-                       value->reg = -1;
+               /* the input value of a binary or unary op is clobbered
+                  by the output value */
+               flags = CLOBBER_INPUT_VALUE;
                }
+       else if(regs->descs[index].clobber)
+       {
+               flags = CLOBBER_INPUT_VALUE;
        }
-
-       /* The registers do not contain values any more */
-       gen->contents[reg].num_values = 0;
-       gen->contents[reg].used_for_temp = 0;
-       if(other_reg != -1)
+       else
        {
-               gen->contents[other_reg].num_values = 0;
-               gen->contents[other_reg].used_for_temp = 0;
+               flags = CLOBBER_NONE;
        }
 
-       /* If the registers are members of a stack, then readjust the
-          stack mappings to compensate for the change */
-       if(gen->contents[reg].remap != -1)
+       if(flags == CLOBBER_NONE)
+       {
+               if(regs->descs[index].value->has_global_register
+                  && regs->descs[index].value->global_reg == reg)
        {
-               free_stack_reg(gen, reg);
+                       return CLOBBER_NONE;
        }
-       if(other_reg != -1 && gen->contents[other_reg].remap != -1)
+               if(regs->descs[index].value->in_register
+                  && regs->descs[index].value->reg == reg)
        {
-               free_stack_reg(gen, other_reg);
-       }
-
-#ifdef JIT_REG_DEBUG
-       dump_regs(gen, "leave free_reg_and_spill");
-#endif
-
-       /* Free the register using CPU-specific code */
-       _jit_gen_free_reg(gen, reg, other_reg, value_used);
-}
-
-/*@
- * @deftypefun void _jit_regs_want_reg (jit_gencode_t gen, int reg, int 
for_long)
- * Tell the register allocator that we want a particular register
- * for a specific purpose.  The current contents of the register
- * are spilled.  If @code{reg} is part of a register pair, then the
- * other register in the pair will also be spilled.  If @code{reg}
- * is a stack register, then it should be the first one.
- *
- * This is typically used for x86 instructions that require operands
- * to be in certain registers (especially multiplication and division),
- * and we want to make sure that the register is free before we clobber it.
- * It is also used to make space in the x86 FPU for floating-point returns.
- *
- * This may return a different pseudo register number if @code{reg}
- * was a member of a stack and some other register was made free.
- * @end deftypefun
address@hidden/
-int _jit_regs_want_reg(jit_gencode_t gen, int reg, int for_long)
-{
-       int other_reg;
-       if((_jit_reg_info[reg].flags & JIT_REG_IN_STACK) == 0)
-       {
-               /* Spill an ordinary register and its pair register */
-               free_reg_and_spill(gen, reg, 0, 1);
-               if(for_long)
-               {
-                       other_reg = _jit_reg_info[reg].other_reg;
-                       if(other_reg != -1)
-                       {
-                               free_reg_and_spill(gen, other_reg, 0, 1);
-                       }
-               }
-               else
-               {
-                       other_reg = -1;
-               }
-
-               /* Mark the register as touched and return it */
-               jit_reg_set_used(gen->touched, reg);
-               if(other_reg != -1)
-               {
-                       jit_reg_set_used(gen->touched, other_reg);
-               }
-               return reg;
-       }
-       else
-       {
-               /* If we want a stack register, all we have to do is roll
-                  everything down to make room for the new value.  If the
-                  stack is full, then we spill the entire stack */
-               return create_stack_reg(gen, reg, 0);
-       }
-}
-
-/*@
- * @deftypefun void _jit_regs_free_reg (jit_gencode_t gen, int reg, int 
value_used)
- * Free the contents of a pseudo register, without spilling.  Used when
- * the contents of a register becomes invalid.  If @code{value_used}
- * is non-zero, then it indicates that the value has already been
- * used.  On some systems, an explicit instruction is needed to free
- * a register whose value hasn't been used yet (e.g. x86 floating point
- * stack registers).
- * @end deftypefun
address@hidden/
-void _jit_regs_free_reg(jit_gencode_t gen, int reg, int value_used)
-{
-#ifdef JIT_REG_DEBUG
-       printf("enter _jit_regs_free_reg(reg = %d, value_used = %d)\n", reg, 
value_used);
-#endif
-
-       free_reg_and_spill(gen, reg, value_used, 0);
-
-#ifdef JIT_REG_DEBUG
-       printf("leave _jit_regs_free_reg\n");
-#endif
-}
-
-/*@
- * @deftypefun void _jit_regs_set_value (jit_gencode_t gen, int reg, 
jit_value_t value, int still_in_frame)
- * Set pseudo register @code{reg} to record that it currently holds the
- * contents of @code{value}.  The value is assumed to already be in
- * the register and no spill occurs.  If @code{still_in_frame} is
- * non-zero, then the value is still in the stack frame; otherwise the
- * value is exclusively in the register.
- * @end deftypefun
address@hidden/
-void _jit_regs_set_value
-       (jit_gencode_t gen, int reg, jit_value_t value, int still_in_frame)
-{
-       int other_reg;
-       int first_stack_reg;
-
-#ifdef JIT_REG_DEBUG
-       dump_regs(gen, "enter set_value");
-#endif
-
-       /* Get the other register in a pair */
-       if(_jit_regs_needs_long_pair(value->type))
-       {
-               other_reg = _jit_reg_info[reg].other_reg;
-       }
-       else
-       {
-               other_reg = -1;
-       }
-
-       /* Mark the register as touched */
-       jit_reg_set_used(gen->touched, reg);
-       if(other_reg != -1)
-       {
-               jit_reg_set_used(gen->touched, other_reg);
-       }
-
-       /* Adjust the allocation state to reflect that "reg" contains "value" */
-       gen->contents[reg].values[0] = value;
-       gen->contents[reg].num_values = 1;
-       gen->contents[reg].age = gen->current_age;
-       if(other_reg == -1)
-       {
-               gen->contents[reg].is_long_start = 0;
-               gen->contents[reg].is_long_end = 0;
-               gen->contents[reg].used_for_temp = 0;
-       }
-       else
-       {
-               gen->contents[reg].is_long_start = 1;
-               gen->contents[reg].is_long_end = 0;
-               gen->contents[reg].used_for_temp = 0;
-               gen->contents[other_reg].num_values = 0;
-               gen->contents[other_reg].is_long_start = 0;
-               gen->contents[other_reg].is_long_end = 1;
-               gen->contents[other_reg].age = gen->current_age;
-               gen->contents[other_reg].used_for_temp = 0;
-       }
-       (gen->current_age)++;
-
-       /* Set the stack mappings for this register */
-       if((_jit_reg_info[reg].flags & JIT_REG_IN_STACK) != 0)
-       {
-               first_stack_reg = reg;
-               while((_jit_reg_info[first_stack_reg].flags & 
JIT_REG_START_STACK) == 0)
-               {
-                       --first_stack_reg;
-               }
-               gen->contents[reg].remap = first_stack_reg;
-               gen->stack_map[first_stack_reg] = reg;
-       }
-
-#ifdef JIT_REG_DEBUG
-       dump_regs(gen, "leave set_value");
-#endif
-
-       /* 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 = (short)reg;
-}
-
-/*@
- * @deftypefun void _jit_regs_set_incoming (jit_gencode_t gen, int reg, 
jit_value_t value)
- * Set pseudo register @code{reg} to record that it currently holds the
- * contents of @code{value}.  If the register was previously in use,
- * then spill its value first.
- * @end deftypefun
address@hidden/
-void _jit_regs_set_incoming(jit_gencode_t gen, int reg, jit_value_t value)
-{
-       /* Eject any values that are currently in the register */
-       reg = _jit_regs_want_reg(gen, reg, 
_jit_regs_needs_long_pair(value->type));
-
-       /* Record that the value is in "reg", but not in the frame */
-       _jit_regs_set_value(gen, reg, value, 0);
-}
-
-/*@
- * @deftypefun void _jit_regs_set_outgoing (jit_gencode_t gen, int reg, 
jit_value_t value)
- * Load the contents of @code{value} into pseudo register @code{reg},
- * spilling out the current contents.  This is used to set up outgoing
- * parameters for a function call.
- * @end deftypefun
address@hidden/
-void _jit_regs_set_outgoing(jit_gencode_t gen, int reg, jit_value_t value)
-{
-       int other_reg;
-       int need_pair;
-
-#ifdef JIT_BACKEND_X86
-       jit_type_t type;
-       type = jit_type_normalize(value->type);
-       need_pair = 0;
-       if(type)
-       {
-               /* We might need to put float values in register pairs under 
x86 */
-               if(type->kind == JIT_TYPE_LONG || type->kind == JIT_TYPE_ULONG 
||
-                  type->kind == JIT_TYPE_FLOAT64 || type->kind == 
JIT_TYPE_NFLOAT)
-               {
-                       need_pair = 1;
-               }
-       }
-       if(value->in_register && value->reg == reg && !need_pair)
-#else
-       need_pair = _jit_regs_needs_long_pair(value->type);
-       if(value->in_register && value->reg == reg)
-#endif
-       {
-               /* The value is already in the register, but we may need to 
spill
-                  if the frame copy is not up to date with the register */
-               if(!(value->in_global_register) && !(value->in_frame) &&
-                  !(value->is_temporary))
-               {
-                       free_reg_and_spill(gen, reg, 1, 1);
-               }
-
-               /* The value is no longer "really" in the register.  A copy is
-                  left behind, but the value itself reverts to the frame copy
-                  as we are about to kill the registers in a function call */
-               value->in_register = 0;
-               value->reg = -1;
-       }
-       else
-       {
-               /* Force the value out of whatever register it is already in */
-               _jit_regs_force_out(gen, value, 0);
-
-               /* Reload the value into the specified register */
-               if(need_pair)
-               {
-               #ifdef JIT_BACKEND_X86
-                       /* Long values in outgoing registers must be in ECX:EDX,
-                          not in the ordinary register pairing of ECX:EBX */
-                       _jit_regs_want_reg(gen, reg, 0);
-                       other_reg = 2;
-                       _jit_regs_want_reg(gen, other_reg, 0);
-               #else
-                       _jit_regs_want_reg(gen, reg, 1);
-                       other_reg = _jit_reg_info[reg].other_reg;
-               #endif
-                       _jit_gen_load_value(gen, reg, other_reg, value);
-                       jit_reg_set_used(gen->inhibit, reg);
-                       jit_reg_set_used(gen->inhibit, other_reg);
-               }
-               else
-               {
-                       _jit_regs_want_reg(gen, reg, 0);
-                       _jit_gen_load_value(gen, reg, -1, value);
-                       jit_reg_set_used(gen->inhibit, reg);
-               }
-       }
-}
-
-/*@
- * @deftypefun int _jit_regs_is_top (jit_gencode_t gen, jit_value_t value)
- * Determine if @code{value} is currently the in top-most position
- * in the appropriate register stack.  Always returns non-zero if
- * @code{value} is in a register, but that register is not part of a
- * register stack.  This is used to check if an operand value is
- * already in the right position for a unary operation.
- * @end deftypefun
address@hidden/
-int _jit_regs_is_top(jit_gencode_t gen, jit_value_t value)
-{
-       int reg, remap;
-       if(!(value->in_register))
-       {
-               return 0;
-       }
-       reg = value->reg;
-       if((_jit_reg_info[reg].flags & JIT_REG_IN_STACK) == 0)
-       {
-               return 1;
-       }
-       remap = gen->contents[reg].remap;
-       if(remap != -1 && (_jit_reg_info[remap].flags & JIT_REG_START_STACK) != 
0)
-       {
-               return 1;
-       }
-       return 0;
-}
-
-/*@
- * @deftypefun int _jit_regs_is_top_two (jit_gencode_t gen, jit_value_t 
value1, jit_value_t value2)
- * Determine if @code{value1} and @code{value2} are in the top two positions
- * in the appropriate register stack, and @code{value2} is above
- * @code{value1}.  Always returns non-zero if @code{value} and
- * @code{value2} are in registers, but those registers are not part
- * of a register stack.  This is used to check if the operand values
- * for a binary operation are already in the right positions.
- * @end deftypefun
address@hidden/
-int _jit_regs_is_top_two
-       (jit_gencode_t gen, jit_value_t value1, jit_value_t value2)
-{
-       int reg, remap;
-       if(!(value1->in_register) || !(value2->in_register))
-       {
-               return 0;
-       }
-       reg = value2->reg;
-       if((_jit_reg_info[reg].flags & JIT_REG_IN_STACK) == 0)
-       {
-               reg = value1->reg;
-               return ((_jit_reg_info[reg].flags & JIT_REG_IN_STACK) == 0);
-       }
-       remap = gen->contents[reg].remap;
-       if(remap == -1 || (_jit_reg_info[remap].flags & JIT_REG_START_STACK) == 
0)
-       {
-               return 0;
-       }
-       reg = value1->reg;
-       if((_jit_reg_info[reg].flags & JIT_REG_IN_STACK) == 0)
-       {
-               return 1;
-       }
-       return (gen->contents[reg].remap == (remap + 1));
-}
-
-/*
- * Load a value into a register.
- */
-static void load_value(jit_gencode_t gen, int reg, int other_reg,
-                                          jit_value_t value, int destroy)
-{
-       _jit_gen_load_value(gen, reg, other_reg, value);
-       if(destroy || value->is_constant)
-       {
-               /* Mark the register as containing a temporary value */
-               gen->contents[reg].used_for_temp = 1;
-               jit_reg_set_used(gen->touched, reg);
-               if(other_reg != -1)
-               {
-                       gen->contents[reg].is_long_start = 1;
-                       gen->contents[other_reg].is_long_end = 1;
-                       gen->contents[other_reg].used_for_temp = 1;
-                       jit_reg_set_used(gen->touched, other_reg);
-               }
-       }
-       else
-       {
-               /* Mark the register as containing the value we have loaded */
-               if(value->has_global_register)
-                       _jit_regs_set_value(gen, reg, value, 
value->in_global_register);
-               else
-                       _jit_regs_set_value(gen, reg, value, value->in_frame);
-       }
-}
-
-/*
- * Find a free register to hold the contents of a value.
- */
-static int free_register_for_value
-       (jit_gencode_t gen, jit_value_t value, int *other_reg)
-{
-       int reg, type;
-       int suitable_reg, need_pair;
-       int suitable_age;
-
-       /* Clear the other register before we start */
-       *other_reg = -1;
-
-       /* Determine if we need a long pair for this value */
-       need_pair = _jit_regs_needs_long_pair(value->type);
-
-       /* Determine the type of register that we need */
-       switch(jit_type_normalize(value->type)->kind)
-       {
-               case JIT_TYPE_SBYTE:
-               case JIT_TYPE_UBYTE:
-               case JIT_TYPE_SHORT:
-               case JIT_TYPE_USHORT:
-               case JIT_TYPE_INT:
-               case JIT_TYPE_UINT:
-               case JIT_TYPE_NINT:
-               case JIT_TYPE_NUINT:
-               case JIT_TYPE_SIGNATURE:
-               case JIT_TYPE_PTR:
-               {
-                       type = JIT_REG_WORD;
-               }
-               break;
-
-               case JIT_TYPE_LONG:
-               case JIT_TYPE_ULONG:
-               {
-                       if(need_pair)
-                               type = JIT_REG_LONG;
-                       else
-                               type = JIT_REG_WORD;
-               }
-               break;
-
-               case JIT_TYPE_FLOAT32:
-               {
-                       type = JIT_REG_FLOAT32;
-               }
-               break;
-
-               case JIT_TYPE_FLOAT64:
-               {
-                       type = JIT_REG_FLOAT64;
-               }
-               break;
-
-               case JIT_TYPE_NFLOAT:
-               {
-                       type = JIT_REG_NFLOAT;
-               }
-               break;
-
-               default: return -1;
-       }
-
-       /* Search for a free register, ignoring permanent global allocations.
-          We also keep track of the oldest suitable register that is not free 
*/
-       suitable_reg = -1;
-       suitable_age = -1;
-       for(reg = 0; reg < JIT_NUM_REGS; ++reg)
-       {
-               if((_jit_reg_info[reg].flags & type) != 0 &&
-                  !jit_reg_is_used(gen->permanent, reg) &&
-                  !jit_reg_is_used(gen->inhibit, reg))
-               {
-                       if((_jit_reg_info[reg].flags & JIT_REG_IN_STACK) != 0)
-                       {
-                               /* We always load stack values to the top of 
the stack */
-                               reg = create_stack_reg(gen, reg, 1);
-                               return reg;
-                       }
-                       else if(!need_pair)
-                       {
-                               if(gen->contents[reg].num_values == 0 &&
-                                  !(gen->contents[reg].used_for_temp) &&
-                                  !(gen->contents[reg].is_long_end))
-                               {
-                                       return reg;
-                               }
-                       }
-                       else
-                       {
-                               *other_reg = _jit_reg_info[reg].other_reg;
-                               if(gen->contents[reg].num_values == 0 &&
-                                  !(gen->contents[reg].used_for_temp) &&
-                                  gen->contents[*other_reg].num_values == 0 &&
-                                  !(gen->contents[*other_reg].used_for_temp))
-                               {
-                                       return reg;
-                               }
-                       }
-                       if(suitable_reg == -1 || gen->contents[reg].age < 
suitable_age)
-                       {
-                               /* This is the oldest suitable register of this 
type */
-                               suitable_reg = reg;
-                               suitable_age = gen->contents[reg].age;
-                       }
-               }
-       }
-
-       /* If there were no suitable registers at all, then fail */
-       if(suitable_reg == -1)
-       {
-               return -1;
-       }
-
-       /* Eject the current contents of the register */
-       reg = _jit_regs_want_reg(gen, suitable_reg, need_pair);
-       if(need_pair)
-       {
-               *other_reg = _jit_reg_info[reg].other_reg;
-       }
-       return reg;
-}
-
-/*@
- * @deftypefun int _jit_regs_load_value (jit_gencode_t gen, jit_value_t value, 
int destroy, int used_again)
- * Load a value into any register that is suitable and return that register.
- * If the value needs a long pair, then this will return the first register
- * in the pair.  Returns -1 if the value will not fit into any register.
- *
- * If @code{destroy} is non-zero, then we are about to destroy the register,
- * so the system must make sure that such destruction will not side-effect
- * @code{value} or any of the other values currently in that register.
- *
- * If @code{used_again} is non-zero, then it indicates that the value is
- * used again further down the block.
- * @end deftypefun
address@hidden/
-int _jit_regs_load_value
-       (jit_gencode_t gen, jit_value_t value, int destroy, int used_again)
-{
-       int reg, other_reg, need_pair;
-
-       /* Determine if we need a long pair for this value */
-       need_pair = _jit_regs_needs_long_pair(value->type);
-
-       /* If the value is already in a register, then try to use that register 
*/
-       if(value->in_register)
-       {
-               reg = value->reg;
-               if(destroy)
-               {
-                       if(gen->contents[reg].num_values == 1 &&
-                          (value->in_frame || value->in_global_register || 
!used_again))
-                       {
-                               /* We are the only value in this register, and 
the
-                                  value is duplicated in the frame, or will 
never
-                                  be used again in this block.  In this case,
-                                  we can disassociate the register from the 
value
-                                  and just return the register as-is */
-                               value->in_register = 0;
-                               gen->contents[reg].num_values = 0;
-                               gen->contents[reg].used_for_temp = 1;
-                               gen->contents[reg].age = gen->current_age;
-                               if(need_pair)
-                               {
-                                       other_reg = 
_jit_reg_info[reg].other_reg;
-                                       gen->contents[other_reg].used_for_temp 
= 1;
-                                       gen->contents[other_reg].age = 
gen->current_age;
-                               }
-                               ++(gen->current_age);
-                               return reg;
-                       }
-                       else
-                       {
-                               /* We need to spill the register and then 
reload it */
-                               spill_register(gen, reg);
-                       }
-               }
-               else
-               {
-                       if(gen->contents[reg].num_values == 1 &&
-                          (value->in_frame || value->in_global_register || 
!used_again))
-                       {
-                               /* We are the only value in this register, and 
the
-                                  value is duplicated in the frame, or will 
never
-                                  be used again in this block.  In this case,
-                                  we can disassociate the register from the 
value
-                                  and just return the register as-is */
-                               value->in_register = 0;
-                               gen->contents[reg].num_values = 0;
-                               gen->contents[reg].used_for_temp = 1;
-                       }
-                       gen->contents[reg].age = gen->current_age;
-                       if(need_pair)
-                       {
-                               other_reg = _jit_reg_info[reg].other_reg;
-                               gen->contents[other_reg].age = gen->current_age;
-                       }
-                       ++(gen->current_age);
-                       return reg;
-               }
-       }
-
-       /* If the value is in a global register, and we are not going
-          to destroy the value, then use the global register itself.
-          This will avoid a redundant register copy operation */
-       if(value->in_global_register && !destroy)
-       {
-               return value->global_reg;
-       }
-
-       /* Search for a free register to hold the value */
-       reg = free_register_for_value(gen, value, &other_reg);
-       load_value(gen, reg, other_reg, value, destroy);
-       return reg;
-}
-
-/*@
- * @deftypefun int _jit_regs_dest_value (jit_gencode_t gen, jit_value_t value)
- * Get a new register to hold @code{value} as a destination.  This cannot
- * be used for stack register destinations (use @code{_jit_regs_new_top}
- * for that).
- * @end deftypefun
address@hidden/
-int _jit_regs_dest_value(jit_gencode_t gen, jit_value_t value)
-{
-       int reg, other_reg;
-
-       /* If the value is exclusively in a register already, then use that */
-       if(value->in_register)
-       {
-               reg = value->reg;
-               if(gen->contents[reg].num_values == 1)
-               {
-                       value->in_frame = 0;
-                       value->in_global_register = 0;
-                       return reg;
-               }
-               free_reg_and_spill(gen, reg, 0, 1);
-       }
-
-       /* Find a suitable register to hold the destination */
-       reg = free_register_for_value(gen, value, &other_reg);
-       _jit_regs_set_value(gen, reg, value, 0);
-       return reg;
-}
-
-/*
- * Determine if "num" stack registers are free in a specific stack.
- */
-static int stack_regs_free(jit_gencode_t gen, int reg, int num)
-{
-       int first_reg;
-
-       /* Find the extents of the stack */
-       while((_jit_reg_info[reg].flags & JIT_REG_START_STACK) == 0)
-       {
-               --reg;
-       }
-       first_reg = reg;
-       while((_jit_reg_info[reg].flags & JIT_REG_END_STACK) == 0)
-       {
-               ++reg;
-       }
-
-       /* Search for free registers */
-       while(reg >= first_reg)
-       {
-               if(gen->contents[reg].num_values == 0 &&
-                  !(gen->contents[reg].used_for_temp))
-               {
-                       --num;
-                       if(num <= 0)
-                       {
-                               return 1;
-                       }
-               }
-               --reg;
-       }
-       return 0;
-}
-
-/*@
- * @deftypefun int _jit_regs_load_to_top (jit_gencode_t gen, jit_value_t 
value, int used_again, int type_reg)
- * Load the contents of @code{value} into a register that is guaranteed to
- * be at the top of its stack.  This is the preferred way to set up for a
- * unary operation on a stack-based architecture.  Returns the pseudo
- * register that contains the value.
- *
- * When @code{value} is loaded, the "destroy" flag is set so that the
- * unary operation will not affect the original contents of @code{value}.
- * The @code{used_again} flag indicates if @code{value} is used again
- * in the current basic block.
- *
- * The @code{type_reg} parameter should be set to the pseudo register
- * number of a suitable register.  This is used to determine which
- * register stack to use for the allocation.
- * @end deftypefun
address@hidden/
-int _jit_regs_load_to_top(jit_gencode_t gen, jit_value_t value, int 
used_again, int type_reg)
-{
-       int reg;
-
-       /* Determine if the value is already in the top-most register */
-       if(value->in_register)
-       {
-               reg = value->reg;
-               if((_jit_reg_info[gen->contents[reg].remap].flags
-                               & JIT_REG_START_STACK) != 0)
-               {
-                       if(value->in_frame || value->in_global_register || 
!used_again)
-                       {
-                               /* Disassociate the value from the register and 
return */
-                               value->in_register = 0;
-                               gen->contents[reg].num_values = 0;
-                               gen->contents[reg].used_for_temp = 1;
-                               gen->contents[reg].age = gen->current_age;
-                               ++(gen->current_age);
-                               return reg;
-                       }
-               }
-               spill_all_stack(gen, type_reg);
-       }
-
-       /* If there are free registers of this type, then load the value now */
-       if(stack_regs_free(gen, type_reg, 1))
-       {
-               return _jit_regs_load_value(gen, value, 1, used_again);
-       }
-
-       /* Spill the entire stack contents, to get things into a known state */
-       spill_all_stack(gen, type_reg);
-
-       /* Reload the value and return */
-       return _jit_regs_load_value(gen, value, 1, used_again);
-}
-
-/*@
- * @deftypefun int _jit_regs_load_to_top_two (jit_gencode_t gen, jit_value_t 
value, jit_value_t value2, int used_again1, int used_again2, int type_reg)
- * Load the contents of @code{value} and @code{value2} into registers that
- * are guaranteed to be at the top of the relevant register stack.
- * This is the preferred way to set up for a binary operation on a
- * stack-based architecture.
- *
- * Returns the pseudo register that contains @code{value}.  The pseudo
- * register that contains @code{value2} is marked as free, because it is
- * assumed that the binary operation will immediately consume its value.
- *
- * When @code{value} are @code{value2} are loaded, the "destroy" flag is
- * set so that the binary operation will not affect their original contents.
- * The @code{used_again1} and @code{used_again2} flags indicate if
- * @code{value} and @code{value2} are used again in the current basic block.
- *
- * The @code{type_reg} parameter should be set to the pseudo register
- * number of a suitable register.  This is used to determine which
- * register stack to use for the allocation.
- * @end deftypefun
address@hidden/
-int _jit_regs_load_to_top_two
-       (jit_gencode_t gen, jit_value_t value, jit_value_t value2,
-        int used_again1, int used_again2, int type_reg)
-{
-       int reg, reg2;
-
-       /* Determine if the values are already in the top two registers */
-       if(value->in_register && value2->in_register)
-       {
-               reg = value->reg;
-               reg2 = value2->reg;
-               if((_jit_reg_info[gen->contents[reg2].remap].flags
-                               & JIT_REG_START_STACK) != 0 &&
-                  gen->contents[reg].remap == (gen->contents[reg2].remap + 1))
-               {
-                       if((value->in_frame || value->in_global_register || 
!used_again1) &&
-                          (value2->in_frame || value2->in_global_register || 
!used_again2))
-                       {
-                               /* Disassociate the values from the registers 
and return */
-                               free_stack_reg(gen, reg2);
-                               value->in_register = 0;
-                               value2->in_register = 0;
-                               gen->contents[reg].num_values = 0;
-                               gen->contents[reg].used_for_temp = 1;
-                               gen->contents[reg].age = gen->current_age;
-                               gen->contents[reg2].num_values = 0;
-                               gen->contents[reg2].used_for_temp = 0;
-                               gen->contents[reg2].age = gen->current_age;
-                               ++(gen->current_age);
-                               return reg;
-                       }
-               }
-               spill_all_stack(gen, type_reg);
-       }
-       else if(value2->in_register && !(value->in_register))
-       {
-               /* We'll probably need to rearrange the stack, so spill first */
-               spill_all_stack(gen, type_reg);
-       }
-
-       /* If there are free registers of this type, then load the values now */
-       if(stack_regs_free(gen, type_reg, 2))
-       {
-               reg = _jit_regs_load_value(gen, value, 1, used_again1);
-               reg2 = _jit_regs_load_value(gen, value2, 1, used_again2);
-               free_stack_reg(gen, reg2);
-               gen->contents[reg2].used_for_temp = 0;
-               return reg;
-       }
-
-       /* Spill the entire stack contents, to get things into a known state */
-       spill_all_stack(gen, type_reg);
-
-       /* Reload the values and return */
-       reg = _jit_regs_load_value(gen, value, 1, used_again1);
-       reg2 = _jit_regs_load_value(gen, value2, 1, used_again2);
-       free_stack_reg(gen, reg2);
-       gen->contents[reg2].used_for_temp = 0;
-       return reg;
-}
-
-/*@
- * @deftypefun void _jit_regs_load_to_top_three (jit_gencode_t gen, 
jit_value_t value, jit_value_t value2, jit_value_t value3, int used_again1, int 
used_again2, int used_again3, int type_reg)
- * Load three values to the top of a register stack.  The values are assumed
- * to be popped by the subsequent operation.  This is used by the interpreted
- * back end for things like array stores, that need three values but all
- * of them are discarded after the operation.
- * @end deftypefun
address@hidden/
-void _jit_regs_load_to_top_three
-       (jit_gencode_t gen, jit_value_t value, jit_value_t value2,
-        jit_value_t value3, int used_again1, int used_again2,
-        int used_again3, int type_reg)
-{
-       int reg, reg2, reg3;
-
-       /* Determine if the values are already in the top three registers */
-       if(value->in_register && value2->in_register && value3->in_register)
-       {
-               reg = value->reg;
-               reg2 = value2->reg;
-               reg3 = value3->reg;
-               if((_jit_reg_info[gen->contents[reg2].remap].flags
-                               & JIT_REG_START_STACK) != 0 &&
-                  gen->contents[reg].remap == (gen->contents[reg2].remap + 1) 
&&
-                  gen->contents[reg2].remap == (gen->contents[reg3].remap + 1))
-               {
-                       if((value->in_frame || value->in_global_register || 
!used_again1) &&
-                          (value2->in_frame || value2->in_global_register ||
-                                               !used_again2) &&
-                          (value3->in_frame || value3->in_global_register || 
!used_again3))
-                       {
-                               /* Disassociate the values from the registers 
and return */
-                               free_stack_reg(gen, reg);
-                               free_stack_reg(gen, reg2);
-                               free_stack_reg(gen, reg3);
-                               value->in_register = 0;
-                               value2->in_register = 0;
-                               value3->in_register = 0;
-                               gen->contents[reg].used_for_temp = 0;
-                               gen->contents[reg2].used_for_temp = 0;
-                               gen->contents[reg3].used_for_temp = 0;
-                               return;
-                       }
-               }
-       }
-
-       /* Spill everything out, so that we know where things are */
-       spill_all_stack(gen, type_reg);
-
-       /* Load the three values that we want onto the stack */
-       reg = _jit_regs_load_value(gen, value, 1, used_again1);
-       reg2 = _jit_regs_load_value(gen, value2, 1, used_again2);
-       reg3 = _jit_regs_load_value(gen, value3, 1, used_again3);
-       gen->contents[reg].used_for_temp = 0;
-       gen->contents[reg2].used_for_temp = 0;
-       gen->contents[reg3].used_for_temp = 0;
-}
-
-/*@
- * @deftypefun int _jit_regs_num_used (jit_gencode_t gen, int type_reg)
- * Get the number of stack registers in use within the register stack
- * indicated by @code{type_reg}.
- * @end deftypefun
address@hidden/
-int _jit_regs_num_used(jit_gencode_t gen, int type_reg)
-{
-       int count;
-       while((_jit_reg_info[type_reg].flags & JIT_REG_START_STACK) == 0)
-       {
-               --type_reg;
-       }
-       count = 0;
-       for(;;)
-       {
-               if(gen->contents[type_reg].num_values > 0 ||
-                  gen->contents[type_reg].used_for_temp)
-               {
-                       ++count;
-               }
-               if((_jit_reg_info[type_reg].flags & JIT_REG_END_STACK) == 0)
-               {
-                       break;
-               }
-               ++type_reg;
-       }
-       return count;
-}
-
-/*@
- * @deftypefun int _jit_regs_new_top (jit_gencode_t gen, jit_value_t value, 
int type_reg)
- * Record that the top of the stack indicated by @code{type_reg} now
- * contains @code{value}.  This is slightly different from
- * @code{_jit_regs_set_value}, in that the register wasn't previously
- * allocated to a temporary operand value.  Returns the actual stack
- * register that contains @code{value}.
- * @end deftypefun
address@hidden/
-int _jit_regs_new_top(jit_gencode_t gen, jit_value_t value, int type_reg)
-{
-       int reg;
-       
-       /* Create space for the value at the top of the stack */
-       reg = create_stack_reg(gen, type_reg, 1);
-
-       /* Record the "value" is now in this register */
-       value->in_register = 1;
-       value->in_frame = 0;
-       value->in_global_register = 0;
-       value->reg = reg;
-       gen->contents[reg].values[0] = value;
-       gen->contents[reg].num_values = 1;
-
-       /* Return the allocated register to the caller */
-       return reg;
-}
-
-/*@
- * @deftypefun void _jit_regs_force_out (jit_gencode_t gen, jit_value_t value, 
int is_dest)
- * If @code{value} is currently in a register, then force its value out
- * into the stack frame.  The @code{is_dest} flag indicates that the value
- * will be a destination, so we don't care about the original value.
- * @end deftypefun
address@hidden/
-void _jit_regs_force_out(jit_gencode_t gen, jit_value_t value, int is_dest)
-{
-       if(value->in_register)
-       {
-               if((_jit_reg_info[value->reg].flags & JIT_REG_IN_STACK) == 0)
-               {
-                       free_reg_and_spill(gen, value->reg, 0, !is_dest);
-               }
-               else
-               {
-                       /* Always do a spill for a stack register */
-                       spill_register(gen, value->reg);
-               }
-       }
-}
-
-/*
- * Minimum number of times a candidate must be used before it
- * is considered worthy of putting in a global register.
- */
-#define        JIT_MIN_USED            3
-
-/*@
- * @deftypefun void _jit_regs_alloc_global (jit_gencode_t gen, jit_function_t 
func)
- * Perform global register allocation on the values in @code{func}.
- * This is called during function compilation just after variable
- * liveness has been computed.
- * @end deftypefun
address@hidden/
-void _jit_regs_alloc_global(jit_gencode_t gen, jit_function_t func)
-{
-#if JIT_NUM_GLOBAL_REGS != 0
-       jit_value_t candidates[JIT_NUM_GLOBAL_REGS];
-       int num_candidates = 0;
-       int index, reg, posn, num;
-       jit_pool_block_t block;
-       jit_value_t value, temp;
-
-       /* If the function has a "try" block, then don't do global allocation
-          as the "longjmp" for exception throws will wipe out global registers 
*/
-       if(func->has_try)
-       {
-               return;
-       }
-
-       /* If the current function involves a tail call, then we don't do
-          global register allocation and we also prevent the code generator
-          from using any of the callee-saved registers.  This simplifies
-          tail calls, which don't have to worry about restoring such registers 
*/
-       if(func->builder->has_tail_call)
-       {
-               for(reg = 0; reg < JIT_NUM_REGS; ++reg)
-               {
-                       if((_jit_reg_info[reg].flags &
-                                       (JIT_REG_FIXED | JIT_REG_CALL_USED)) == 
0)
-                       {
-                               jit_reg_set_used(gen->permanent, reg);
-                       }
-               }
-               return;
-       }
-
-       /* Scan all values within the function, looking for the most used.
-          We will replace this with a better allocation strategy later */
-       block = func->builder->value_pool.blocks;
-       num = (int)(func->builder->value_pool.elems_per_block);
-       while(block != 0)
-       {
-               if(!(block->next))
-               {
-                       num = (int)(func->builder->value_pool.elems_in_last);
-               }
-               for(posn = 0; posn < num; ++posn)
-               {
-                       value = (jit_value_t)(block->data + posn *
-                                                                 sizeof(struct 
_jit_value));
-                       if(value->global_candidate && value->usage_count >= 
JIT_MIN_USED &&
-                          !(value->is_addressable) && !(value->is_volatile))
-                       {
-                               /* Insert this candidate into the list, ordered 
on count */
-                               index = 0;
-                               while(index < num_candidates &&
-                                     value->usage_count <= 
candidates[index]->usage_count)
-                               {
-                                       ++index;
-                               }
-                               while(index < num_candidates)
-                               {
-                                       temp = candidates[index];
-                                       candidates[index] = value;
-                                       value = temp;
-                                       ++index;
-                               }
-                               if(index < JIT_NUM_GLOBAL_REGS)
-                               {
-                                       candidates[num_candidates++] = value;
-                               }
-                       }
-               }
-               block = block->next;
-       }
-
-       /* Allocate registers to the candidates.  We allocate from the top-most
-          register in the allocation order, because some architectures like
-          PPC require global registers to be saved top-down for efficiency */
-       reg = JIT_NUM_REGS - 1;
-       for(index = 0; index < num_candidates; ++index)
-       {
-               while(reg >= 0 && (_jit_reg_info[reg].flags & JIT_REG_GLOBAL) 
== 0)
-               {
-                       --reg;
-               }
-               candidates[index]->has_global_register = 1;
-               candidates[index]->global_reg = (short)reg;
-               jit_reg_set_used(gen->touched, reg);
-               jit_reg_set_used(gen->permanent, reg);
-               --reg;
-       }
-
-#endif
-}
-
-/*
- * @deftypefun void _jit_regs_get_reg_pair (jit_gencode_t gen, int not_this1, 
int not_this2, int not_this3, {int *} reg, {int *} reg2)
- * Get a register pair for temporary operations on "long" values.
- * @end deftypefun
- */
-void _jit_regs_get_reg_pair(jit_gencode_t gen, int not_this1, int not_this2,
-                                                   int not_this3, int *reg, 
int *reg2)
-{
-       int index;
-       for(index = 0; index < 8; ++index)
-       {
-               if((_jit_reg_info[index].flags & JIT_REG_WORD) == 0 ||
-                  jit_reg_is_used(gen->permanent, index))
-               {
-                       continue;
-               }
-               if(index != not_this1 && index != not_this2 &&
-                  index != not_this3)
-               {
-                       break;
-               }
-       }
-       *reg = index;
-       _jit_regs_want_reg(gen, index, 0);
-       if(!reg2)
-       {
-               return;
-       }
-       for(; index < 8; ++index)
-       {
-               if((_jit_reg_info[index].flags & JIT_REG_WORD) == 0 ||
-                  jit_reg_is_used(gen->permanent, index))
-               {
-                       continue;
-               }
-               if(index != not_this1 && index != not_this2 &&
-                  index != not_this3 && index != *reg)
-               {
-                       break;
-               }
-       }
-       if(index >= 8)
-       {
-               *reg2 = -1;
-       }
-       else
-       {
-               *reg2 = index;
-               _jit_regs_want_reg(gen, index, 0);
-       }
-}
-
-/*
- * 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
-
-#define COST_COPY              4
-#define COST_SPILL_DIRTY       16
-#define COST_SPILL_DIRTY_GLOBAL        2
-#define COST_SPILL_CLEAN       1
-#define COST_SPILL_CLEAN_GLOBAL        1
-#define COST_GLOBAL_BIAS       1
-#define COST_THRASH            32
-#define COST_CLOBBER_GLOBAL    1000
-
-#ifdef JIT_BACKEND_X86
-# define ALLOW_CLOBBER_GLOBAL  1
-#else
-# define ALLOW_CLOBBER_GLOBAL  0
-#endif
-
-/* Value usage flags. */
-#define VALUE_INPUT            1
-#define VALUE_USED             2
-#define VALUE_LIVE             4
-#define VALUE_DEAD             8
-
-/* Clobber flags. */
-#define CLOBBER_NONE           0
-#define CLOBBER_INPUT_VALUE    1
-#define CLOBBER_REG            2
-#define CLOBBER_OTHER_REG      4
-
-/*
- * For a stack register find the first stack register.
- */
-static int
-get_stack_start(int reg)
-{
-       if(IS_STACK_REG(reg))
-       {
-               while(!IS_STACK_START(reg))
-               {
-                       --reg;
-               }
-       }
-       return reg;
-}
-
-/*
- * Find the stack top given the first stack register,
- */
-static int
-get_stack_top(jit_gencode_t gen, int stack_start)
-{
-       if(gen->stack_map[stack_start] < 0)
-       {
-               return (stack_start - 1);
-       }
-       return (gen->stack_map[stack_start]);
-}
-
-/*
- * Find the start register of a long pair given the end register.
- */
-static int
-get_long_pair_start(int other_reg)
-{
-       int reg;
-       for(reg = 0; reg < JIT_NUM_REGS; reg++)
-       {
-               if(other_reg == OTHER_REG(reg))
-               {
-                       return reg;
-               }
-       }
-       return -1;
-}
-
-/*
- * Determine the type of register that we need.
- */
-static int
-get_register_type(jit_value_t value, int need_pair)
-{
-       switch(jit_type_normalize(value->type)->kind)
-       {
-       case JIT_TYPE_SBYTE:
-       case JIT_TYPE_UBYTE:
-       case JIT_TYPE_SHORT:
-       case JIT_TYPE_USHORT:
-       case JIT_TYPE_INT:
-       case JIT_TYPE_UINT:
-       case JIT_TYPE_NINT:
-       case JIT_TYPE_NUINT:
-       case JIT_TYPE_SIGNATURE:
-       case JIT_TYPE_PTR:
-               return JIT_REG_WORD;
-
-       case JIT_TYPE_LONG:
-       case JIT_TYPE_ULONG:
-               return need_pair ? JIT_REG_LONG : JIT_REG_WORD;
-
-       case JIT_TYPE_FLOAT32:
-               return JIT_REG_FLOAT32;
-
-       case JIT_TYPE_FLOAT64:
-               return JIT_REG_FLOAT64;
-
-       case JIT_TYPE_NFLOAT:
-               return JIT_REG_NFLOAT;
-       }
-
-       return 0;
-}
-
-/*
- * Check if two values are known to be equal.
- */
-static int
-are_values_equal(_jit_regdesc_t *desc1, _jit_regdesc_t *desc2)
-{
-       if(desc1 && desc2 && desc1->value && desc2->value)
-       {
-               if(desc1->value == desc2->value)
-               {
-                       return 1;
-               }
-               if(desc1->value->in_register && desc2->value->in_register)
-               {
-                       return desc1->value->reg == desc2->value->reg;
-               }
-       }
-       return 0;
-}
-
-
-/*
- * Get value usage and liveness information. The accurate liveness data is
- * only available for values used by the current instruction.
- *
- * VALUE_INPUT flag is set if the value is one of the instruction's inputs.
- *
- * VALUE_LIVE and VALUE_USED flags are set for input values only according
- * to the liveness flags provided along with the instruction.
- *
- * VALUE_DEAD flag is set in two cases. First, it is always set for output
- * values. Second, it is set for input values that are neither live nor used.
- *
- * These flags are used when spilling a register. In this case we generally
- * do not know if the values in the register are used by the instruction. If
- * the VALUE_INPUT flag is present then it is so and the value has to be held
- * in the register for the instruction to succeed. If the VALUE_DEAD flag is
- * present then there is no need to spill the value and it may be discarded.
- * Otherwise the value must be spilled.
- *
- * The VALUE_LIVE and VALUE_USED flags may only be set for input values of
- * the instruction. For other values these flags are not set even if they are
- * perfectly alive. These flags are used as a hint for spill cost calculation.
- *
- * NOTE: The output value is considered to be dead because the instruction is
- * just about to recompute it so there is no point to save it.
- *
- * Generally, a value becomes dead just after the instruction that used it
- * last time. The allocator frees dead values after each instruction so it
- * might seem that there is no chance to find any dead value on the current
- * instruction. However if the value is used by the current instruction both
- * as the input and output then it was alive after the last instruction and
- * hence was not freed. Also the old allocator might sometimes leave a dead
- * value in the register and as of this writing the old allocator is still
- * used by some rules. And just in case if some dead value may creep through
- * the new allocator...
- */
-static int
-value_usage(_jit_regs_t *regs, jit_value_t value)
-{
-       int flags;
-
-       flags = 0;
-       if(value->is_constant)
-       {
-               flags |= VALUE_DEAD;
-       }
-       if(value == regs->descs[0].value)
-       {
-               if(regs->ternary)
-               {
-                       flags |= VALUE_INPUT;
-                       if(regs->descs[0].used)
-                       {
-                               flags |= VALUE_LIVE | VALUE_USED;
-                       }
-                       else if(regs->descs[0].live)
-                       {
-                               flags |= VALUE_LIVE;
-                       }
-                       else
-                       {
-                               flags |= VALUE_DEAD;
-                       }
-               }
-               else
-               {
-                       flags |= VALUE_DEAD;
-               }
-       }
-       if(value == regs->descs[1].value)
-       {
-               flags |= VALUE_INPUT;
-               if(regs->descs[1].used)
-               {
-                       flags |= VALUE_LIVE | VALUE_USED;
-               }
-               else if(regs->descs[1].live)
-               {
-                       flags |= VALUE_LIVE;
-               }
-               else
-               {
-                       flags |= VALUE_DEAD;
-               }
-       }
-       if(value == regs->descs[2].value)
-       {
-               flags |= VALUE_INPUT;
-               if(regs->descs[2].used)
-               {
-                       flags |= VALUE_LIVE | VALUE_USED;
-               }
-               else if(regs->descs[2].live)
-               {
-                       flags |= VALUE_LIVE;
-               }
-               else
-               {
-                       flags |= VALUE_DEAD;
-               }
-       }
-       return flags;
-}
-
-/*
- * Check if the register contains any live values.
- */
-static int
-is_register_alive(jit_gencode_t gen, _jit_regs_t *regs, int reg)
-{
-       int index, usage;
-
-       if(reg < 0)
-       {
-               return 0;
-       }
-
-       /* Assume that a global register is always alive unless it is to be
-          computed right away. */
-       if(jit_reg_is_used(gen->permanent, reg))
-       {
-               if(!regs->ternary
-                  && regs->descs[0].value
-                  && regs->descs[0].value->has_global_register
-                  && regs->descs[0].value->global_reg == reg)
-               {
-                       return 0;
-               }
-               return 1;
-       }
-
-       if(gen->contents[reg].is_long_end)
-       {
-               reg = get_long_pair_start(reg);
-       }
-       for(index = 0; index < gen->contents[reg].num_values; index++)
-       {
-               usage = value_usage(regs, gen->contents[reg].values[index]);
-               if((usage & VALUE_DEAD) == 0)
-               {
-                       return 1;
-               }
-       }
-
-       return 0;
-}
-
-/*
- * Determine the effect of using a register for a value. This includes the
- * following:
- *  - whether the value is clobbered by the instruction;
- *  - whether the previous contents of the register is clobbered.
- *
- * The value is clobbered by the instruction if it is used as input value
- * and the output value will go to the same register and these two values
- * are not equal. Or the instruction has a side effect that destroys the
- * input value regardless of the output. This is indicated with the
- * CLOBBER_INPUT_VALUE flag.
- *
- * The previous content is clobbered if the register contains any non-dead
- * values that are destroyed by loading the input value, by computing the
- * output value, or as a side effect of the instruction.
- *
- * The previous content is not clobbered if the register contains only dead
- * values or it is used for input value that is already in the register so
- * there is no need to load it and at the same time the instruction has no
- * side effects that destroy the input value or the register is used for
- * output value and the only value it contained before is the same value.
- *
- * The flag CLOBBER_REG indicates if the previous content of the register is
- * clobbered. The flag CLOBBER_OTHER_REG indicates that the other register
- * in a long pair is clobbered.
- *
- */
-static int
-clobbers_register(jit_gencode_t gen, _jit_regs_t *regs, int index, int reg, 
int other_reg)
-{
-       int flags;
-
-       if(!regs->descs[index].value)
-       {
-               return CLOBBER_NONE;
-       }
-
-       if(regs->ternary || !regs->descs[0].value)
-       {
-               /* this is either a ternary or binary or unary note */
-               if(IS_STACK_REG(reg) || regs->descs[index].clobber)
-               {
-                       flags = CLOBBER_INPUT_VALUE;
-               }
-               else
-               {
-                       flags = CLOBBER_NONE;
-               }
-       }
-       else if(index == 0)
-       {
-               /* this is the output value of a binary or unary op */
-               flags = CLOBBER_NONE;
-               if(is_register_alive(gen, regs, reg))
-               {
-                       flags |= CLOBBER_REG;
-               }
-               if(is_register_alive(gen, regs, other_reg))
-               {
-                       flags |= CLOBBER_OTHER_REG;
-               }
-               return flags;
-       }
-       else if(regs->on_stack && !regs->no_pop)
-       {
-               /* this is a binary or unary stack op -- the input value
-                  is either popped or overwritten by the output */
-               flags = CLOBBER_INPUT_VALUE;
-       }
-       else if(reg == regs->descs[0].reg
-               || reg == regs->descs[0].other_reg
-               || other_reg == regs->descs[0].reg)
-       {
-               /* the input value of a binary or unary op is clobbered
-                  by the output value */
-               flags = CLOBBER_INPUT_VALUE;
-       }
-       else if(regs->descs[index].clobber)
-       {
-               flags = CLOBBER_INPUT_VALUE;
-       }
-       else
-       {
-               flags = CLOBBER_NONE;
-       }
-
-       if(flags == CLOBBER_NONE)
-       {
-               if(regs->descs[index].value->has_global_register
-                  && regs->descs[index].value->global_reg == reg)
-               {
-                       return CLOBBER_NONE;
-               }
-               if(regs->descs[index].value->in_register
-                  && regs->descs[index].value->reg == reg)
-               {
-                       return CLOBBER_NONE;
-               }
+                       return CLOBBER_NONE;
+               }
        }
 
        if(is_register_alive(gen, regs, reg))
@@ -2152,7 +573,7 @@
 set_regdesc_flags(jit_gencode_t gen, _jit_regs_t *regs, int index)
 {
        _jit_regdesc_t *desc;
-       int reg, other_reg, stack_start;
+       int reg, other_reg;
        int clobber, clobber_input;
 
 #ifdef JIT_REG_DEBUG
@@ -2211,19 +632,6 @@
                jit_reg_set_used(regs->clobber, desc->other_reg);
        }
 
-#if 0
-       /* See if the input value is clobbered by the output. */
-       if(index > 0 && !regs->ternary
-          && (desc->reg == regs->descs[0].reg
-              || desc->reg == regs->descs[0].other_reg
-              || (desc->other_reg >= 0
-                  && (desc->other_reg == regs->descs[0].reg
-                      || desc->other_reg == regs->descs[0].other_reg))))
-       {
-               clobber_input = 1;
-       }
-#endif
-
        /* See if the input value is thrashed by other inputs or clobbered
           by the output. The allocator tries to avoid thrashing so it may
           only take place if the register is assigned explicitly. For x87
@@ -2350,18 +758,8 @@
                desc->kill = 1;
        }
 
-       if(IS_STACK_REG(desc->reg))
-       {
-               stack_start = get_stack_start(desc->reg);
-               if(regs->stack_start < 0)
-               {
-                       regs->stack_start = stack_start;
-               }
-               else if(stack_start != regs->stack_start)
-               {
-                       return 0;
-               }
-
+       if(IS_STACK_REG(desc->reg))
+       {
                if(index > 0 || regs->ternary)
                {
                        ++(regs->wanted_stack_count);
@@ -2452,135 +850,454 @@
                {
                        if(value->in_global_register)
                        {
-                               cost += COST_SPILL_CLEAN_GLOBAL;
+                               cost += COST_SPILL_CLEAN_GLOBAL;
+                       }
+                       else
+                       {
+                               cost += COST_SPILL_DIRTY_GLOBAL;
+                       }
+               }
+               else
+               {
+                       if(value->in_frame)
+                       {
+                               cost += COST_SPILL_CLEAN;
+                       }
+                       else
+                       {
+                               cost += COST_SPILL_DIRTY;
+                       }
+               }
+       }
+       if(other_reg >= 0)
+       {
+               for(index = 0; index < gen->contents[other_reg].num_values; 
index++)
+               {
+                       value = gen->contents[other_reg].values[index];
+                       usage = value_usage(regs, value);
+                       if((usage & VALUE_DEAD) != 0)
+                       {
+                               /* the value is not spilled */
+                               continue;
+                       }
+                       if((usage & VALUE_LIVE) != 0 && (usage & VALUE_USED) == 
0)
+                       {
+                               /* the value has to be spilled anyway */
+                               /* NOTE: This is true for local register 
allocation,
+                                  review for future global allocator. */
+                               continue;
+                       }
+                       if(value->has_global_register)
+                       {
+                               if(value->in_global_register)
+                               {
+                                       cost += COST_SPILL_CLEAN_GLOBAL;
+                               }
+                               else
+                               {
+                                       cost += COST_SPILL_DIRTY_GLOBAL;
+                               }
+                       }
+                       else
+                       {
+                               if(value->in_frame)
+                               {
+                                       cost += COST_SPILL_CLEAN;
+                               }
+                               else
+                               {
+                                       cost += COST_SPILL_DIRTY;
+                               }
+                       }
+               }
+       }
+       return cost;
+}
+
+static int
+thrashes_value(jit_gencode_t gen,
+              _jit_regdesc_t *desc, int reg, int other_reg,
+              _jit_regdesc_t *desc2)
+{
+       int reg2, other_reg2;
+
+#if ALLOW_CLOBBER_GLOBAL
+       if(desc2->value->has_global_register)
+       {
+               if(desc2->value->global_reg == reg)
+               {
+                       if(desc && desc2->value == desc->value)
+                       {
+                               return 0;
+                       }
+                       return 1;
+               }
+               if(desc2->value->global_reg == other_reg)
+               {
+                       return 1;
+               }
+       }
+#endif
+
+       if(desc2->value->in_register)
+       {
+               reg2 = desc2->value->reg;
+               if(reg2 == reg)
+               {
+                       if(are_values_equal(desc2, desc))
+                       {
+                               return 0;
+                       }
+                       return 1;
+               }
+               if(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;
+                       }
+               }
+       }
+
+       return 0;
+}
+
+static int
+choose_scratch_register(jit_gencode_t gen, _jit_regs_t *regs, int index)
+{
+       int reg, type;
+       int use_cost, spill_cost;
+       int suitable_reg;
+       int suitable_cost;
+       int suitable_age;
+
+       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(jit_reg_is_used(regs->assigned, reg))
+               {
+                       continue;
+               }
+               if(!jit_reg_is_used(regs->scratch[index].regset, reg))
+               {
+                       continue;
+               }
+
+#if ALLOW_CLOBBER_GLOBAL
+               if(jit_reg_is_used(gen->permanent, reg))
+               {
+                       use_cost = COST_CLOBBER_GLOBAL;
+               }
+               else
+               {
+                       use_cost = 0;
+               }
+#else
+               if(jit_reg_is_used(gen->permanent, reg))
+               {
+                       continue;
+               }
+               use_cost = 0;
+#endif
+
+               if(regs->ternary && regs->descs[0].value
+                  && thrashes_value(gen, 0, reg, -1, &regs->descs[0]))
+               {
+                       use_cost += COST_THRASH;
+               }
+               else if(regs->descs[1].value
+                       && thrashes_value(gen, 0, reg, -1, &regs->descs[1]))
+               {
+                       use_cost += COST_THRASH;
+               }
+               else if(regs->descs[2].value
+                       && thrashes_value(gen, 0, reg, -1, &regs->descs[2]))
+               {
+                       use_cost += COST_THRASH;
+               }
+
+               spill_cost = compute_spill_cost(gen, regs, reg, -1);
+
+               if((use_cost + spill_cost) < suitable_cost
+                  || (spill_cost > 0 && (use_cost + spill_cost) == 
suitable_cost
+                      && gen->contents[reg].age < suitable_age))
+               {
+                       suitable_reg = reg;
+                       suitable_cost = use_cost + spill_cost;
+                       suitable_age = gen->contents[reg].age;
+               }
+       }
+
+       if(suitable_reg >= 0)
+       {
+               set_scratch_register(gen, regs, index, suitable_reg);
+               return 1;
+       }
+
+       return 0;
+}
+
+static int
+choose_output_register(jit_gencode_t gen, _jit_regs_t *regs)
+{
+       int type, need_pair;
+       int reg, other_reg;
+       int use_cost, spill_cost;
+       int suitable_reg, suitable_other_reg;
+       int suitable_cost;
+       int suitable_age;
+
+       need_pair = _jit_regs_needs_long_pair(regs->descs[0].value->type);
+       type = get_register_type(regs->descs[0].value, need_pair);
+       if(!type)
+       {
+               return 0;
+       }
+
+       suitable_reg = -1;
+       suitable_other_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(jit_reg_is_used(gen->inhibit, reg))
+               {
+                       continue;
+               }
+               if(!jit_reg_is_used(regs->descs[0].regset, reg))
+               {
+                       continue;
+               }
+
+               if(need_pair)
+               {
+                       other_reg = OTHER_REG(reg);
+                       if(jit_reg_is_used(gen->inhibit, other_reg))
+                       {
+                               continue;
+                       }
+               }
+               else
+               {
+                       other_reg = -1;
+               }
+
+               /* It is not allowed to assign an output value to a global 
register
+                  unless it is the very value the global register contains. */
+               if(jit_reg_is_used(gen->permanent, reg))
+               {
+                       if(regs->descs[0].value->has_global_register
+                          && regs->descs[0].value->global_reg == reg)
+                       {
+                               use_cost = 0;
                        }
                        else
                        {
-                               cost += COST_SPILL_DIRTY_GLOBAL;
+                               continue;
                        }
                }
                else
                {
-                       if(value->in_frame)
+                       if(other_reg >= 0 && jit_reg_is_used(gen->permanent, 
other_reg))
                        {
-                               cost += COST_SPILL_CLEAN;
+                               continue;
                        }
-                       else
+                       if(regs->descs[0].value->has_global_register)
                        {
-                               cost += COST_SPILL_DIRTY;
+                               use_cost = COST_GLOBAL_BIAS;
                        }
+                       else
+                       {
+                               use_cost = 0;
                }
        }
-       if(other_reg >= 0)
-       {
-               for(index = 0; index < gen->contents[other_reg].num_values; 
index++)
-               {
-                       value = gen->contents[other_reg].values[index];
-                       usage = value_usage(regs, value);
-                       if((usage & VALUE_DEAD) != 0)
+
+               if(regs->free_dest)
                        {
-                               /* the value is not spilled */
-                               continue;
+                       /* noop */
                        }
-                       if((usage & VALUE_LIVE) != 0 && (usage & VALUE_USED) == 
0)
+               else if(regs->descs[1].value
+                       && regs->descs[1].value->in_register
+                       && regs->descs[1].value->reg == reg)
                        {
-                               /* the value has to be spilled anyway */
-                               /* NOTE: This is true for local register 
allocation,
-                                  review for future global allocator. */
-                               continue;
+                       /* noop */
                        }
-                       if(value->has_global_register)
+               else if(regs->descs[2].value
+                       && regs->descs[2].value->in_register
+                       && regs->descs[2].value->reg == reg)
                        {
-                               if(value->in_global_register)
+                       if(regs->commutative || regs->x87_arith)
                                {
-                                       cost += COST_SPILL_CLEAN_GLOBAL;
+                               /* noop */
                                }
                                else
                                {
-                                       cost += COST_SPILL_DIRTY_GLOBAL;
+                               use_cost += COST_THRASH;
                                }
                        }
                        else
                        {
-                               if(value->in_frame)
-                               {
-                                       cost += COST_SPILL_CLEAN;
+                       use_cost += COST_COPY;
                                }
-                               else
+
+               spill_cost = compute_spill_cost(gen, regs, reg, other_reg);
+
+               if((use_cost + spill_cost) < suitable_cost
+                  || (spill_cost > 0 && (use_cost + spill_cost) == 
suitable_cost
+                      && gen->contents[reg].age < suitable_age))
                                {
-                                       cost += COST_SPILL_DIRTY;
-                               }
+                       suitable_reg = reg;
+                       suitable_other_reg = other_reg;
+                       suitable_cost = use_cost + spill_cost;
+                       suitable_age = gen->contents[reg].age;
                        }
                }
+
+       if(suitable_reg >= 0)
+       {
+               set_regdesc_register(gen, regs, 0, suitable_reg, 
suitable_other_reg);
+               return 1;
        }
-       return cost;
+
+       return 0;
 }
 
-static int
-thrashes_value(jit_gencode_t gen,
-              _jit_regdesc_t *desc, int reg, int other_reg,
-              _jit_regdesc_t *desc2)
+/*
+ * 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
+choose_input_order(jit_gencode_t gen, _jit_regs_t *regs)
 {
-       int reg2, other_reg2;
+       _jit_regdesc_t temp_desc;
+       int keep1, keep2;
 
-#if ALLOW_CLOBBER_GLOBAL
-       if(desc2->value->has_global_register)
+       if(regs->ternary || regs->free_dest || !regs->descs[0].value)
        {
-               if(desc2->value->global_reg == reg)
+               regs->dest_input_index = 0;
+               return;
+       }
+
+       if(regs->descs[2].value
+          && regs->descs[2].value->in_register
+          && regs->descs[2].value->reg == regs->descs[0].reg
+          && regs->descs[2].value != regs->descs[1].value)
                {
-                       if(desc && desc2->value == desc->value)
+               if(regs->on_stack && regs->x87_arith)
                        {
-                               return 0;
+                       regs->no_pop = 1;
+                       regs->reverse_dest = 1;
+                       regs->dest_input_index = 2;
                        }
-                       return 1;
+               else
+               {
+                       if(regs->commutative)
+                       {
+                               temp_desc = regs->descs[1];
+                               regs->descs[1] = regs->descs[2];
+                               regs->descs[2] = temp_desc;
                }
-               if(desc2->value->global_reg == other_reg)
+                       regs->dest_input_index = 1;
+               }
+       }
+       else if(regs->descs[1].value)
                {
-                       return 1;
+               regs->dest_input_index = 1;
                }
+       else
+       {
+               regs->dest_input_index = 0;
        }
-#endif
 
-       if(desc2->value->in_register)
-       {
-               reg2 = desc2->value->reg;
-               if(reg2 == reg)
+       /* Choose between pop and no-pop instructions. */
+       if(regs->on_stack && regs->x87_arith && !regs->no_pop
+          && !regs->clobber_all && !regs->clobber_stack
+          && regs->descs[1].value && regs->descs[2].value)
                {
-                       if(are_values_equal(desc2, desc))
+               /* Determine if we might want to keep either of input values
+                  in registers after the instruction completion. */
+               if(regs->descs[1].value->in_register)
                        {
-                               return 0;
-                       }
-                       return 1;
+                       keep1 = is_register_alive(gen, regs, 
regs->descs[1].value->reg);
                }
-               if(reg2 == other_reg)
+               else
                {
-                       return 1;
+                       keep1 = (regs->descs[1].used
+                                && (regs->descs[1].value != 
regs->descs[0].value)
+                                && !regs->descs[1].clobber);
                }
-               if(gen->contents[reg2].is_long_start)
-               {
-                       other_reg2 = OTHER_REG(reg2);
-                       if(other_reg2 == reg /*|| other_reg2 == other_reg*/)
+               if(regs->descs[2].value->in_register)
                        {
-                               return 1;
-                       }
+                       keep2 = is_register_alive(gen, regs, 
regs->descs[2].value->reg);
                }
+               else
+               {
+                       keep2 = (regs->descs[2].used
+                                && (regs->descs[2].value != 
regs->descs[0].value)
+                                && !regs->descs[2].clobber);
        }
 
-       return 0;
+               regs->no_pop = (keep1 || keep2);
+       }
 }
 
 static int
-choose_scratch_register(jit_gencode_t gen, _jit_regs_t *regs, int index)
+choose_input_register(jit_gencode_t gen, _jit_regs_t *regs, int index)
 {
-       int reg, type;
+       _jit_regdesc_t *desc;
+       _jit_regdesc_t *desc2;
+       int type, need_pair;
+       int reg, other_reg;
        int use_cost, spill_cost;
-       int suitable_reg;
+       int suitable_reg, suitable_other_reg;
        int suitable_cost;
        int suitable_age;
+       int clobber;
 
-       type = JIT_REG_WORD;
+       desc = &regs->descs[index];
+       if(!desc->value)
+       {
+               return 0;
+       }
+
+       need_pair = _jit_regs_needs_long_pair(desc->value->type);
+       type = get_register_type(desc->value, need_pair);
+       if(!type)
+       {
+               return 0;
+       }
+
+       if(index == regs->dest_input_index)
+       {
+               desc2 = &regs->descs[0];
+       }
+       else
+       {
+               desc2 = desc;
+       }
 
        suitable_reg = -1;
+       suitable_other_reg = -1;
        suitable_cost = COST_TOO_MUCH;
        suitable_age = -1;
        for(reg = 0; reg < JIT_NUM_REGS; reg++)
@@ -2593,51 +1310,102 @@
                {
                        continue;
                }
-               if(!jit_reg_is_used(regs->scratch[index].regset, reg))
+               if(!jit_reg_is_used(desc->regset, reg))
+               {
+                       continue;
+               }
+
+               if(need_pair)
+               {
+                       other_reg = OTHER_REG(reg);
+                       if(jit_reg_is_used(regs->assigned, other_reg))
+                       {
+                               continue;
+                       }
+               }
+               else
+               {
+                       other_reg = -1;
+               }
+
+               if((desc->value->in_global_register && desc->value->global_reg 
== reg)
+                  || (desc->value->in_register && desc->value->reg == reg))
+               {
+                       use_cost = 0;
+               }
+               else
+               {
+                       use_cost = COST_COPY;
+               }
+               if(desc2->value->has_global_register && 
desc2->value->global_reg != reg)
+               {
+                       use_cost += COST_GLOBAL_BIAS;
+               }
+
+               if(index != 0 && regs->ternary && regs->descs[0].value
+                  && thrashes_value(gen, desc, reg, other_reg, 
&regs->descs[0]))
+               {
+                       use_cost += COST_THRASH;
+               }
+               else if(index != 1 && regs->descs[1].value
+                       && thrashes_value(gen, desc, reg, other_reg, 
&regs->descs[1]))
+               {
+                       use_cost += COST_THRASH;
+               }
+               else if(index != 2 && regs->descs[2].value
+                       && thrashes_value(gen, desc, reg, other_reg, 
&regs->descs[2]))
+               {
+                       use_cost += COST_THRASH;
+               }
+
+               clobber = clobbers_register(gen, regs, index, reg, other_reg);
+               if((clobber & CLOBBER_INPUT_VALUE) != 0)
+               {
+                       if(desc->used)
+                       {
+                               use_cost += COST_SPILL_CLEAN;
+                       }
+               }
+               if((clobber & (CLOBBER_REG | CLOBBER_OTHER_REG)) != 0)
+               {
+                       if(jit_reg_is_used(gen->permanent, reg))
+                       {
+                               continue;
+                       }
+#if !ALLOW_CLOBBER_GLOBAL
+                       if(other_reg >= 0 && jit_reg_is_used(gen->permanent, 
other_reg))
                {
                        continue;
                }
-
-#if ALLOW_CLOBBER_GLOBAL
-               if(jit_reg_is_used(gen->permanent, reg))
+#endif
+                       if(jit_reg_is_used(regs->clobber, reg)
+                          || (other_reg >= 0 && jit_reg_is_used(regs->clobber, 
other_reg)))
                {
-                       use_cost = COST_CLOBBER_GLOBAL;
+                               spill_cost = 0;
                }
                else
                {
-                       use_cost = 0;
+                               spill_cost = compute_spill_cost(gen, regs, reg, 
other_reg);
                }
-#else
-               if(jit_reg_is_used(gen->permanent, reg))
+#if ALLOW_CLOBBER_GLOBAL
+                       if(other_reg >= 0 && jit_reg_is_used(gen->permanent, 
other_reg))
                {
-                       continue;
+                               spill_cost += COST_CLOBBER_GLOBAL;
                }
-               use_cost = 0;
 #endif
-
-               if(regs->ternary && regs->descs[0].value
-                  && thrashes_value(gen, 0, reg, -1, &regs->descs[0]))
-               {
-                       use_cost += COST_THRASH;
-               }
-               else if(regs->descs[1].value
-                       && thrashes_value(gen, 0, reg, -1, &regs->descs[1]))
-               {
-                       use_cost += COST_THRASH;
                }
-               else if(regs->descs[2].value
-                       && thrashes_value(gen, 0, reg, -1, &regs->descs[2]))
+               else
                {
-                       use_cost += COST_THRASH;
+                       spill_cost = 0;
                }
 
-               spill_cost = compute_spill_cost(gen, regs, reg, -1);
-
                if((use_cost + spill_cost) < suitable_cost
                   || (spill_cost > 0 && (use_cost + spill_cost) == 
suitable_cost
                       && gen->contents[reg].age < suitable_age))
                {
+                       /* This is the oldest suitable register of this type */
                        suitable_reg = reg;
+                       suitable_other_reg = other_reg;
                        suitable_cost = use_cost + spill_cost;
                        suitable_age = gen->contents[reg].age;
                }
@@ -2645,1027 +1413,1229 @@
 
        if(suitable_reg >= 0)
        {
-               set_scratch_register(gen, regs, index, suitable_reg);
+               set_regdesc_register(gen, regs, index, suitable_reg, 
suitable_other_reg);
                return 1;
        }
 
        return 0;
 }
 
-static int
-choose_output_register(jit_gencode_t gen, _jit_regs_t *regs)
+/*
+ * 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)
 {
-       int type, need_pair;
-       int reg, other_reg;
-       int use_cost, spill_cost;
-       int suitable_reg, suitable_other_reg;
-       int suitable_cost;
-       int suitable_age;
-
-       need_pair = _jit_regs_needs_long_pair(regs->descs[0].value->type);
-       type = get_register_type(regs->descs[0].value, need_pair);
-       if(!type)
+       if((!regs->on_stack || regs->x87_arith)
+          && are_values_equal(desc1, desc2)
+          && desc1->reg >= 0 && desc2->reg < 0
+          && !desc1->early_clobber && !desc2->early_clobber)
        {
-               return 0;
+               desc2->reg = desc1->reg;
+               desc2->other_reg = desc1->other_reg;
+               desc2->duplicate = 1;
        }
+}
 
-       suitable_reg = -1;
-       suitable_other_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)
+#ifdef JIT_REG_STACK
+static void
+adjust_assignment(jit_gencode_t gen, _jit_regs_t *regs, int index)
+{
+       _jit_regdesc_t *desc;
+
+       desc = &regs->descs[index];
+       if(!desc->value || !IS_STACK_REG(desc->reg))
                {
-                       continue;
+               return;
                }
-               if(jit_reg_is_used(gen->inhibit, reg))
+
+       if(regs->wanted_stack_count == 1)
                {
-                       continue;
+               /* either a unary op or a binary op with duplicate value */
+               desc->reg = gen->reg_stack_top - regs->loaded_stack_count;
                }
-               if(!jit_reg_is_used(regs->descs[0].regset, reg))
+       else if(regs->wanted_stack_count == 2)
                {
-                       continue;
-               }
+               /* a binary op */
 
-               if(need_pair)
-               {
-                       other_reg = OTHER_REG(reg);
-                       if(jit_reg_is_used(gen->inhibit, other_reg))
+               /* find the input value the output goes to */
+               if(index == 0)
                        {
-                               continue;
+                       index = regs->dest_input_index;
                        }
+
+               if(regs->x87_arith && desc->value->in_register && !desc->copy)
+               {
+                       desc->reg = desc->value->reg;
                }
                else
                {
-                       other_reg = -1;
+                       desc->reg = gen->reg_stack_top - 
regs->loaded_stack_count + index - 1;
                }
+       }
+}
+#endif
 
-               /* It is not allowed to assign an output value to a global 
register
-                  unless it is the very value the global register contains. */
-               if(jit_reg_is_used(gen->permanent, reg))
+#ifdef JIT_REG_STACK
+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))
                {
-                       if(regs->descs[0].value->has_global_register
-                          && regs->descs[0].value->global_reg == reg)
+               desc1 = &regs->descs[1];
+               desc2 = &regs->descs[2];
+
+               if(desc1->value->in_register && !desc1->copy
+                  && desc2->value->in_register && !desc2->copy)
                        {
-                               use_cost = 0;
-                       }
-                       else
+                       /* Is any of the input values on the stack top? */
+                       if(desc1->value->reg == (gen->reg_stack_top - 1))
                        {
-                               continue;
+                               top_index = 1;
                        }
+                       else if(desc2->value->reg == (gen->reg_stack_top - 1))
+                       {
+                               top_index = 2;
                }
                else
                {
-                       if(other_reg >= 0 && jit_reg_is_used(gen->permanent, 
other_reg))
+                               /* TODO: 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 && !desc1->copy)
                        {
-                               continue;
+                       top_index = 2;
                        }
-                       if(regs->descs[0].value->has_global_register)
+               else if(desc2->value->in_register && !desc2->copy)
                        {
-                               use_cost = COST_GLOBAL_BIAS;
+                       top_index = 1;
                        }
                        else
                        {
-                               use_cost = 0;
-                       }
+                       /* TODO: see if the next instruction wants output or 
remaining
+                          input to be on the stack top. */
+                       top_index = 2;
                }
 
-               if(regs->free_dest)
+               if(top_index == 1)
                {
-                       /* noop */
-               }
-               else if(regs->descs[1].value
-                       && regs->descs[1].value->in_register
-                       && regs->descs[1].value->reg == reg)
+                       if(regs->reversible)
                {
-                       /* noop */
+                               regs->reverse_args = 1;
                }
-               else if(regs->descs[2].value
-                       && regs->descs[2].value->in_register
-                       && regs->descs[2].value->reg == reg)
-               {
-                       if(regs->commutative || regs->x87_arith)
+                       else /*if(regs->commutative)*/
                        {
-                               /* noop */
+                               temp_desc = *desc1;
+                               *desc1 = *desc2;
+                               *desc2 = temp_desc;
                        }
-                       else
-                       {
-                               use_cost += COST_THRASH;
+                       regs->reverse_dest ^= 1;
                        }
                }
-               else
+}
+#endif
+
+/*
+ * Associate a temporary with register.
+ */
+static void
+bind_temporary(jit_gencode_t gen, int reg, int other_reg)
+{
+#ifdef JIT_REG_DEBUG
+       printf("bind_temporary(reg = %d, other_reg = %d)\n", reg, other_reg);
+#endif
+
+       gen->contents[reg].num_values = 0;
+       gen->contents[reg].age = 0;
+       gen->contents[reg].used_for_temp = 1;
+       gen->contents[reg].is_long_end = 0;
+       gen->contents[reg].is_long_start = 0;
+       if(other_reg >= 0)
                {
-                       use_cost += COST_COPY;
+               gen->contents[other_reg].num_values = 0;
+               gen->contents[other_reg].age = 0;
+               gen->contents[other_reg].used_for_temp = 1;
+               gen->contents[other_reg].is_long_end = 0;
+               gen->contents[other_reg].is_long_start = 0;
                }
+}
 
-               spill_cost = compute_spill_cost(gen, regs, reg, other_reg);
+/*
+ * Associate value with register.
+ */
+static void
+bind_value(jit_gencode_t gen, jit_value_t value, int reg, int other_reg, int 
still_in_frame)
+{
+#ifdef JIT_REG_DEBUG
+       printf("bind_value(value = ");
+       jit_dump_value(stdout, jit_value_get_function(value), value, 0);
+       printf(", reg = %d, other_reg = %d, still_in_frame = %d)\n",
+              reg, other_reg, still_in_frame);
+#endif
 
-               if((use_cost + spill_cost) < suitable_cost
-                  || (spill_cost > 0 && (use_cost + spill_cost) == 
suitable_cost
-                      && gen->contents[reg].age < suitable_age))
+       if(value->has_global_register && value->global_reg == reg)
                {
-                       suitable_reg = reg;
-                       suitable_other_reg = other_reg;
-                       suitable_cost = use_cost + spill_cost;
-                       suitable_age = gen->contents[reg].age;
+               value->in_register = 0;
+               value->in_global_register = 1;
+               return;
+       }
+
+       if(value->is_constant)
+       {
+               still_in_frame = 0;
+       }
+
+       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);
 
-       if(suitable_reg >= 0)
+       /* Adjust the value to reflect that it is in "reg", and maybe the frame 
*/
+       value->in_register = 1;
+       if(value->has_global_register)
        {
-               set_regdesc_register(gen, regs, 0, suitable_reg, 
suitable_other_reg);
-               return 1;
+               value->in_global_register = still_in_frame;
        }
-
-       return 0;
+       else
+       {
+               value->in_frame = still_in_frame;
+       }
+       value->reg = reg;
 }
 
 /*
- * 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.
+ * Disassociate value with register.
  */
 static void
-choose_input_order(jit_gencode_t gen, _jit_regs_t *regs)
+unbind_value(jit_gencode_t gen, jit_value_t value, int reg, int other_reg)
 {
-       _jit_regdesc_t temp_desc;
-       int keep1, keep2;
+       int index;
 
-       if(regs->ternary || regs->free_dest || !regs->descs[0].value)
+#ifdef JIT_REG_DEBUG
+       printf("unbind_value(value = ");
+       jit_dump_value(stdout, jit_value_get_function(value), value, 0);
+       printf(", reg = %d, other_reg = %d)\n", reg, other_reg);
+#endif
+
+       if(!value->in_register || value->reg != reg)
        {
-               regs->dest_input_index = 0;
                return;
        }
 
-       if(regs->descs[2].value
-          && regs->descs[2].value->in_register
-          && regs->descs[2].value->reg == regs->descs[0].reg
-          && regs->descs[2].value != regs->descs[1].value)
-       {
-               if(regs->on_stack && regs->x87_arith)
-               {
-                       regs->no_pop = 1;
-                       regs->reverse_dest = 1;
-                       regs->dest_input_index = 2;
-               }
-               else
-               {
-                       if(regs->commutative)
-                       {
-                               temp_desc = regs->descs[1];
-                               regs->descs[1] = regs->descs[2];
-                               regs->descs[2] = temp_desc;
-                       }
-                       regs->dest_input_index = 1;
-               }
-       }
-       else if(regs->descs[1].value)
-       {
-               regs->dest_input_index = 1;
-       }
-       else
-       {
-               regs->dest_input_index = 0;
-       }
+       value->in_register = 0;
+       value->reg = -1;
 
-       /* Choose between pop and no-pop instructions. */
-       if(regs->on_stack && regs->x87_arith && !regs->no_pop
-          && !regs->clobber_all && !regs->clobber_stack
-          && regs->descs[1].value && regs->descs[2].value)
+       for(index = gen->contents[reg].num_values - 1; index >= 0; --index)
        {
-               /* Determine if we might want to keep either of input values
-                  in registers after the instruction completion. */
-               if(regs->descs[1].value->in_register)
+               if(gen->contents[reg].values[index] == value)
                {
-                       keep1 = is_register_alive(gen, regs, 
regs->descs[1].value->reg);
-               }
-               else
+                       --(gen->contents[reg].num_values);
+                       for(; index < gen->contents[reg].num_values; index++)
                {
-                       keep1 = (regs->descs[1].used
-                                && (regs->descs[1].value != 
regs->descs[0].value)
-                                && !regs->descs[1].clobber);
+                               gen->contents[reg].values[index] = 
gen->contents[reg].values[index + 1];
                }
-               if(regs->descs[2].value->in_register)
-               {
-                       keep2 = is_register_alive(gen, regs, 
regs->descs[2].value->reg);
+                       break;
                }
-               else
-               {
-                       keep2 = (regs->descs[2].used
-                                && (regs->descs[2].value != 
regs->descs[0].value)
-                                && !regs->descs[2].clobber);
                }
 
-               regs->no_pop = (keep1 || keep2);
+       if(gen->contents[reg].num_values == 0 && other_reg >= 0)
+       {
+               gen->contents[reg].is_long_start = 0;
+               gen->contents[other_reg].is_long_end = 0;
        }
 }
 
-static int
-choose_input_register(jit_gencode_t gen, _jit_regs_t *regs, int index)
+/*
+ * 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.
+ */
+#ifdef JIT_REG_STACK
+static void
+exch_stack_top(jit_gencode_t gen, int reg, int pop)
 {
-       _jit_regdesc_t *desc;
-       _jit_regdesc_t *desc2;
-       int type, need_pair;
-       int reg, other_reg;
-       int use_cost, spill_cost;
-       int suitable_reg, suitable_other_reg;
-       int suitable_cost;
-       int suitable_age;
-       int clobber;
+       int top, index;
+       int num_values, used_for_temp, age;
+       jit_value_t value1, value2;
 
-       desc = &regs->descs[index];
-       if(!desc->value)
-       {
-               return 0;
-       }
+#ifdef JIT_REG_DEBUG
+       printf("exch_stack_top(reg = %d, pop = %d)\n", reg, pop);
+#endif
 
-       need_pair = _jit_regs_needs_long_pair(desc->value->type);
-       type = get_register_type(desc->value, need_pair);
-       if(!type)
+       if(!IS_STACK_REG(reg))
        {
-               return 0;
+               return;
        }
 
-       if(index == regs->dest_input_index)
+       /* Find the top of the stack. */
+       top = gen->reg_stack_top - 1;
+
+       if(pop)
        {
-               desc2 = &regs->descs[0];
+               /* Generate move/pop-top instruction. */
+               _jit_gen_move_top(gen, reg);
+               --(gen->reg_stack_top);
        }
        else
        {
-               desc2 = desc;
+               /* Generate exchange instruction. */
+               _jit_gen_exch_top(gen, reg);
        }
 
-       suitable_reg = -1;
-       suitable_other_reg = -1;
-       suitable_cost = COST_TOO_MUCH;
-       suitable_age = -1;
-       for(reg = 0; reg < JIT_NUM_REGS; reg++)
+       /* Update information about the contents of the registers.  */
+       for(index = 0;
+           index < gen->contents[reg].num_values || index < 
gen->contents[top].num_values;
+           index++)
        {
-               if((_jit_reg_info[reg].flags & type) == 0)
+               value1 = (index < gen->contents[top].num_values
+                         ? gen->contents[top].values[index] : 0);
+               value2 = (index < gen->contents[reg].num_values
+                         ? gen->contents[reg].values[index] : 0);
+
+               if(value1)
                {
-                       continue;
+                       value1->reg = reg;
                }
-               if(jit_reg_is_used(regs->assigned, reg))
+               gen->contents[reg].values[index] = value1;
+
+               if(pop)
                {
-                       continue;
-               }
-               if(!jit_reg_is_used(desc->regset, reg))
+                       if(value2)
                {
-                       continue;
+                               value2->reg = -1;
                }
-
-               if(need_pair)
+                       gen->contents[top].values[index] = 0;
+               }
+               else
                {
-                       other_reg = OTHER_REG(reg);
-                       if(jit_reg_is_used(regs->assigned, other_reg))
+                       if(value2)
                        {
-                               continue;
+                               value2->reg = top;
                        }
+                       gen->contents[top].values[index] = value2;
+               }
+       }
+
+       if(pop)
+       {
+               num_values = 0;
+               used_for_temp = 0;
+               age = 0;
                }
                else
                {
-                       other_reg = -1;
+               num_values = gen->contents[reg].num_values;
+               used_for_temp = gen->contents[reg].used_for_temp;
+               age = gen->contents[reg].age;
                }
+       gen->contents[reg].num_values = gen->contents[top].num_values;
+       gen->contents[reg].used_for_temp = gen->contents[top].used_for_temp;
+       gen->contents[reg].age = gen->contents[top].age;
+       gen->contents[top].num_values = num_values;
+       gen->contents[top].used_for_temp = used_for_temp;
+       gen->contents[top].age = age;
+}
+#endif
 
-               if((desc->value->in_global_register && desc->value->global_reg 
== reg)
-                  || (desc->value->in_register && desc->value->reg == reg))
+/*
+ * Drop value from the register and optionally bind a temporary value in place 
of it.
+ */
+static void
+free_value(jit_gencode_t gen, jit_value_t value, int reg, int other_reg, int 
temp)
+{
+#ifdef JIT_REG_DEBUG
+       printf("free_value(value = ");
+       jit_dump_value(stdout, jit_value_get_function(value), value, 0);
+       printf(", reg = %d, other_reg = %d)\n", reg, other_reg);
+#endif
+
+       /* Never free global registers. */
+       if(value->has_global_register && value->global_reg == reg)
                {
-                       use_cost = 0;
+               return;
                }
-               else
+
+       if(gen->contents[reg].num_values == 1)
                {
-                       use_cost = COST_COPY;
+               if(temp)
+               {
+                       unbind_value(gen, value, reg, other_reg);
+                       bind_temporary(gen, reg, other_reg);
+                       return;
                }
-               if(desc2->value->has_global_register && 
desc2->value->global_reg != reg)
+#ifdef JIT_REG_STACK
+               if(IS_STACK_REG(reg))
                {
-                       use_cost += COST_GLOBAL_BIAS;
+                       /* Free stack register. */
+                       exch_stack_top(gen, reg, 1);
+               }
+#endif
                }
 
-               if(index != 0 && regs->ternary && regs->descs[0].value
-                  && thrashes_value(gen, desc, reg, other_reg, 
&regs->descs[0]))
+       unbind_value(gen, value, reg, other_reg);
+}
+
+/*
+ * Save the value from the register into its frame position and optionally 
free it.
+ * If the value is already in the frame or is a constant then it is not saved 
but
+ * the free option still applies to them.
+ */
+static void
+save_value(jit_gencode_t gen, jit_value_t value, int reg, int other_reg, int 
free)
+{
+#ifdef JIT_REG_DEBUG
+       printf("save_value(value = ");
+       jit_dump_value(stdout, jit_value_get_function(value), value, 0);
+       printf(", reg = %d, other_reg = %d)\n", reg, other_reg);
+#endif
+       /* First take care of values that reside in global registers. */
+       if(value->has_global_register)
                {
-                       use_cost += COST_THRASH;
+               /* Never free global registers. */
+               if(value->global_reg == reg)
+               {
+                       return;
                }
-               else if(index != 1 && regs->descs[1].value
-                       && thrashes_value(gen, desc, reg, other_reg, 
&regs->descs[1]))
+
+               if(!value->in_global_register)
                {
-                       use_cost += COST_THRASH;
+                       _jit_gen_spill_reg(gen, reg, other_reg, value);
+                       value->in_global_register = 1;
                }
-               else if(index != 2 && regs->descs[2].value
-                       && thrashes_value(gen, desc, reg, other_reg, 
&regs->descs[2]))
+               if(free)
                {
-                       use_cost += COST_THRASH;
+                       unbind_value(gen, value, reg, other_reg);
+               }
+               return;
                }
 
-               clobber = clobbers_register(gen, regs, index, reg, other_reg);
-               if((clobber & CLOBBER_INPUT_VALUE) != 0)
+       /* Take care of constants and values that are already in frame. */
+       if(value->is_constant || value->in_frame)
                {
-                       if(desc->used)
+               if(free)
                        {
-                               use_cost += COST_SPILL_CLEAN;
+                       free_value(gen, value, reg, other_reg, (free == 2));
                        }
+               return;
                }
-               if((clobber & (CLOBBER_REG | CLOBBER_OTHER_REG)) != 0)
-               {
-                       if(jit_reg_is_used(gen->permanent, reg))
+
+       /* Now really save the value into the frame. */
+#ifdef JIT_REG_STACK
+       if(IS_STACK_REG(reg))
                        {
-                               continue;
-                       }
-#if !ALLOW_CLOBBER_GLOBAL
-                       if(other_reg >= 0 && jit_reg_is_used(gen->permanent, 
other_reg))
+               int top;
+
+               /* Find the top of the stack. */
+               top = gen->reg_stack_top - 1;
+
+               /* Move the value on the stack top if it is not already there. 
*/
+               if(top != reg)
                        {
-                               continue;
+                       exch_stack_top(gen, reg, 0);
                        }
-#endif
-                       if(jit_reg_is_used(regs->clobber, reg)
-                          || (other_reg >= 0 && jit_reg_is_used(regs->clobber, 
other_reg)))
+
+               if(free && gen->contents[top].num_values == 1)
                        {
-                               spill_cost = 0;
+                       _jit_gen_spill_top(gen, top, value, 1);
+                       --(gen->reg_stack_top);
                        }
                        else
                        {
-                               spill_cost = compute_spill_cost(gen, regs, reg, 
other_reg);
-                       }
-#if ALLOW_CLOBBER_GLOBAL
-                       if(other_reg >= 0 && jit_reg_is_used(gen->permanent, 
other_reg))
-                       {
-                               spill_cost += COST_CLOBBER_GLOBAL;
+                       _jit_gen_spill_top(gen, top, value, 0);
                        }
-#endif
                }
                else
+#endif
                {
-                       spill_cost = 0;
-               }
-
-               if((use_cost + spill_cost) < suitable_cost
-                  || (spill_cost > 0 && (use_cost + spill_cost) == 
suitable_cost
-                      && gen->contents[reg].age < suitable_age))
-               {
-                       /* This is the oldest suitable register of this type */
-                       suitable_reg = reg;
-                       suitable_other_reg = other_reg;
-                       suitable_cost = use_cost + spill_cost;
-                       suitable_age = gen->contents[reg].age;
-               }
+               _jit_gen_spill_reg(gen, reg, other_reg, value);
        }
 
-       if(suitable_reg >= 0)
+       if(free)
        {
-               set_regdesc_register(gen, regs, index, suitable_reg, 
suitable_other_reg);
-               return 1;
+               unbind_value(gen, value, reg, other_reg);
        }
-
-       return 0;
+       value->in_frame = 1;
 }
 
 /*
- * 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.
+ * Spill a specific register.
  */
 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->duplicate = 1;
-       }
-}
-
-static void
-adjust_assignment(jit_gencode_t gen, _jit_regs_t *regs, int index)
+spill_register(jit_gencode_t gen, int reg)
 {
-       _jit_regdesc_t *desc;
-
-       desc = &regs->descs[index];
-       if(!desc->value || !IS_STACK_REG(desc->reg))
-       {
-               return;
-       }
+       int other_reg, index;
+       jit_value_t value;
 
-       if(regs->wanted_stack_count == 1)
-       {
-               /* either a unary op or binary x87 op with duplicate value */
-               desc->reg = regs->current_stack_top - regs->loaded_stack_count 
+ 1;
-       }
-       else if(regs->wanted_stack_count == 2)
-       {
-               /* a binary op */
+#ifdef JIT_REG_DEBUG
+       printf("spill_register(reg = %d)\n", reg);
+#endif
 
-               /* find the input value the output goes to */
-               if(index == 0)
+       /* Find the other register in a long pair */
+       if(gen->contents[reg].is_long_start)
                {
-                       index = 1 + (regs->reverse_dest ^ regs->reverse_args);
+               other_reg = OTHER_REG(reg);
                }
-
-               if(regs->x87_arith && desc->value->in_register && !desc->copy)
+       else if(gen->contents[reg].is_long_end)
                {
-                       desc->reg = desc->value->reg;
+               other_reg = reg;
+               reg = get_long_pair_start(reg);
                }
                else
                {
-                       desc->reg = regs->current_stack_top - 
regs->loaded_stack_count + index;
-               }
+               other_reg = -1;
        }
-       else if(regs->wanted_stack_count == 3)
+
+       for(index = gen->contents[reg].num_values - 1; index >= 0; --index)
        {
-               /* a ternary op */
-               desc->reg = regs->current_stack_top - regs->loaded_stack_count 
+ index + 1;
+               value = gen->contents[reg].values[index];
+               save_value(gen, value, reg, other_reg, 1);
        }
 }
 
+/*
+ * Spill a register clobbered by the instruction.
+ */
 static void
-select_stack_order(jit_gencode_t gen, _jit_regs_t *regs)
+spill_clobbered_register(jit_gencode_t gen, _jit_regs_t *regs, int reg)
 {
-       _jit_regdesc_t *desc1;
-       _jit_regdesc_t *desc2;
-       _jit_regdesc_t temp_desc;
-       int top_index;
+       int other_reg, index, usage;
+       jit_value_t value;
 
-       /* 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];
+#ifdef JIT_REG_DEBUG
+       printf("spill_clobbered_register(reg = %d)\n", reg);
+#endif
 
-               if(desc1->value->in_register && !desc1->copy
-                  && desc2->value->in_register && !desc2->copy)
-               {
-                       /* Is any of the input values is on the stack top? */
-                       if(desc1->value->reg == regs->current_stack_top)
+       /* Find the other register in a long pair */
+       if(gen->contents[reg].is_long_start)
                        {
-                               top_index = 1;
+               other_reg = OTHER_REG(reg);
                        }
-                       else if(desc1->value->reg == regs->current_stack_top)
+       else if(gen->contents[reg].is_long_end)
                        {
-                               top_index = 2;
+               other_reg = reg;
+               reg = get_long_pair_start(reg);
                        }
                        else
                        {
-                               /* TODO: See if the next instruction wants 
output
-                                  or remaining input to be on the stack top. */
-                               top_index = 2;
-                       }
+               other_reg = -1;
                }
-               else if(desc1->value->in_register && !desc1->copy)
+
+       /* Spill register contents in two passes. First free values that
+          do not reqiure spilling then spill those that do. This approach
+          is only useful in case a stack register contains both kinds of
+          values and the last value is one that does not require spilling.
+          This way we may save one free instruction. */
+       if(IS_STACK_REG(reg))
                {
-                       top_index = 2;
+               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_DEAD) != 0 || value->in_frame))
+                       {
+                               free_value(gen, value, reg, other_reg, 0);
                }
-               else if(desc2->value->in_register && !desc2->copy)
+               }
+       }
+       for(index = gen->contents[reg].num_values - 1; index >= 0; --index)
                {
-                       top_index = 1;
+               value = gen->contents[reg].values[index];
+               usage = value_usage(regs, value);
+               if((usage & VALUE_DEAD) == 0)
+               {
+                       if((usage & VALUE_INPUT) == 0)
+                       {
+                               save_value(gen, value, reg, other_reg, 1);
                }
                else
                {
-                       /* TODO: see if the next instruction wants output or 
remaining
-                          input to be on the stack top. */
-                       top_index = 2;
+                               save_value(gen, value, reg, other_reg, 0);
                }
-
-               if(top_index == 1)
-               {
-                       if(regs->reversible)
-                       {
-                               regs->reverse_args = 1;
                        }
-                       else /*if(regs->commutative)*/
+               else
                        {
-                               temp_desc = *desc1;
-                               *desc1 = *desc2;
-                               *desc2 = temp_desc;
+                       if((usage & VALUE_INPUT) == 0)
+                       {
+                               free_value(gen, value, reg, other_reg, 0);
                        }
-                       regs->reverse_dest ^= 1;
                }
        }
 }
 
 static void
-remap_stack_up(jit_gencode_t gen, int stack_start, int reg)
+update_age(jit_gencode_t gen, _jit_regdesc_t *desc)
 {
-       int index;
-
-#ifdef JIT_REG_DEBUG
-       printf("remap_stack_up(stack_start = %d, reg = %d)\n", stack_start, 
reg);
-#endif
+       int reg, other_reg;
 
-       for(index = stack_start; index < reg; index++)
+       reg = desc->value->reg;
+       if(gen->contents[reg].is_long_start)
        {
-               if(gen->contents[index].remap >= 0)
+               other_reg = OTHER_REG(reg);
+       }
+       else
                {
-                       ++(gen->contents[index].remap);
-                       gen->stack_map[gen->contents[index].remap] = index;
+               other_reg = -1;
                }
+
+       gen->contents[reg].age = gen->current_age;
+       if(other_reg >= 0)
+       {
+               gen->contents[other_reg].age = gen->current_age;
        }
-       gen->contents[reg].remap = stack_start;
-       gen->stack_map[stack_start] = reg;
+       ++(gen->current_age);
 }
 
 static void
-remap_stack_down(jit_gencode_t gen, int stack_start, int reg)
+save_input_value(jit_gencode_t gen, _jit_regs_t *regs, int index)
 {
-       int index;
+       _jit_regdesc_t *desc;
+       int reg, other_reg;
 
 #ifdef JIT_REG_DEBUG
-       printf("remap_stack_down(stack_start = %d, reg = %d)\n", stack_start, 
reg);
+       printf("save_input_value(%d)\n", index);
 #endif
 
-       gen->stack_map[gen->contents[stack_start].remap] = -1;
-       for(index = stack_start; index < reg; index++)
+       desc = &regs->descs[index];
+       if(!(desc->value && desc->value->in_register && desc->save))
        {
-               if(gen->contents[index].remap >= 0)
+               return;
+       }
+
+       reg = desc->value->reg;
+       if(gen->contents[reg].is_long_start)
                {
-                       --(gen->contents[index].remap);
-                       gen->stack_map[gen->contents[index].remap] = index;
+               other_reg = OTHER_REG(reg);
                }
+       else
+       {
+               other_reg = -1;
        }
-       gen->contents[reg].remap = -1;
-}
 
-/*
- * Associate a temporary with register.
- */
-static void
-bind_temporary(jit_gencode_t gen, int reg, int other_reg)
-{
-#ifdef JIT_REG_DEBUG
-       printf("bind_temporary(reg = %d, other_reg = %d)\n", reg, other_reg);
-#endif
-
-       gen->contents[reg].num_values = 0;
-       gen->contents[reg].age = 0;
-       gen->contents[reg].used_for_temp = 1;
-       gen->contents[reg].is_long_end = 0;
-       gen->contents[reg].is_long_start = 0;
-       if(other_reg >= 0)
+       if(desc->thrash)
        {
-               gen->contents[other_reg].num_values = 0;
-               gen->contents[other_reg].age = 0;
-               gen->contents[other_reg].used_for_temp = 1;
-               gen->contents[other_reg].is_long_end = 0;
-               gen->contents[other_reg].is_long_start = 0;
+               save_value(gen, desc->value, reg, other_reg, 1);
+       }
+       else
+       {
+               save_value(gen, desc->value, reg, other_reg, 0);
        }
 }
 
-/*
- * Associate value with register.
- */
 static void
-bind_value(jit_gencode_t gen, jit_value_t value, int reg, int other_reg, int 
still_in_frame)
+free_output_value(jit_gencode_t gen, _jit_regs_t *regs)
 {
+       _jit_regdesc_t *desc;
+       int reg, other_reg;
+
 #ifdef JIT_REG_DEBUG
-       printf("bind_value(value = ");
-       jit_dump_value(stdout, jit_value_get_function(value), value, 0);
-       printf(", reg = %d, other_reg = %d, still_in_frame = %d)\n",
-              reg, other_reg, still_in_frame);
+       printf("free_output_value()\n");
 #endif
 
-       if(value->has_global_register && value->global_reg == reg)
+       desc = &regs->descs[0];
+       if(!(desc->value && desc->value->in_register))
        {
-               value->in_register = 0;
-               value->in_global_register = 1;
                return;
        }
-
-       if(value->is_constant)
+       if(desc->value == regs->descs[1].value || desc->value == 
regs->descs[2].value)
        {
-               still_in_frame = 0;
+               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)
+       reg = desc->value->reg;
+       if(gen->contents[reg].is_long_start)
        {
-               gen->contents[reg].is_long_start = 0;
+               other_reg = OTHER_REG(reg);
        }
        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;
+               other_reg = -1;
        }
-       ++(gen->current_age);
 
-       /* 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;
+       free_value(gen, desc->value, reg, other_reg, 0);
 }
 
-/*
- * Disassociate value with register.
- */
 static void
-unbind_value(jit_gencode_t gen, jit_value_t value, int reg, int other_reg)
+load_input_value(jit_gencode_t gen, _jit_regs_t *regs, int index)
 {
-       int index;
+       _jit_regdesc_t *desc;
 
 #ifdef JIT_REG_DEBUG
-       printf("unbind_value(value = ");
-       jit_dump_value(stdout, jit_value_get_function(value), value, 0);
-       printf(", reg = %d, other_reg = %d)\n", reg, other_reg);
+       printf("load_input_value(%d)\n", index);
 #endif
 
-       if(!value->in_register || value->reg != reg)
+       desc = &regs->descs[index];
+       if(!desc->value || desc->duplicate)
        {
                return;
        }
 
-       value->in_register = 0;
-       value->reg = -1;
-
-       for(index = gen->contents[reg].num_values - 1; index >= 0; --index)
+       if(desc->value->has_global_register)
        {
-               if(gen->contents[reg].values[index] == value)
+               if(desc->value->in_global_register && desc->value->global_reg 
== desc->reg)
                {
-                       --(gen->contents[reg].num_values);
-                       for(; index < gen->contents[reg].num_values; index++)
+                       return;
+               }
+               if(desc->value->in_register && desc->value->reg == desc->reg)
                        {
-                               gen->contents[reg].values[index] = 
gen->contents[reg].values[index + 1];
+                       update_age(gen, desc);
+                       return;
                        }
-                       break;
+               _jit_gen_load_value(gen, desc->reg, desc->other_reg, 
desc->value);
+       }
+       else if(desc->value->in_register)
+       {
+               if(desc->value->reg == desc->reg)
+               {
+                       update_age(gen, desc);
+                       if(IS_STACK_REG(desc->reg))
+                       {
+                               desc->stack_reg = desc->reg;
                }
+                       return;
        }
 
-       if(gen->contents[reg].num_values == 0 && other_reg >= 0)
+#ifdef JIT_REG_STACK
+               if(IS_STACK_REG(desc->reg))
        {
-               gen->contents[reg].is_long_start = 0;
-               gen->contents[other_reg].is_long_end = 0;
+                       _jit_gen_load_value(gen, gen->reg_stack_top, -1, 
desc->value);
+                       desc->stack_reg = gen->reg_stack_top++;
+                       bind_temporary(gen, desc->stack_reg, -1);
+               }
+               else
+#endif
+               {
+                       _jit_gen_load_value(gen, desc->reg, desc->other_reg, 
desc->value);
+                       bind_temporary(gen, desc->reg, desc->other_reg);
+               }
+       }
+       else
+       {
+#ifdef JIT_REG_STACK
+               if(IS_STACK_REG(desc->reg))
+               {
+                       _jit_gen_load_value(gen, gen->reg_stack_top, -1, 
desc->value);
+                       desc->stack_reg = gen->reg_stack_top++;
+                       bind_value(gen, desc->value, desc->stack_reg, -1, 1);
+               }
+               else
+#endif
+               {
+                       _jit_gen_load_value(gen, desc->reg, desc->other_reg, 
desc->value);
+                       bind_value(gen, desc->value, desc->reg, 
desc->other_reg, 1);
+               }
        }
 }
 
-/*
- * 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.
- */
+#ifdef JIT_REG_STACK
 static void
-exch_stack_top(jit_gencode_t gen, int reg, int pop)
+move_input_value(jit_gencode_t gen, _jit_regs_t *regs, int index)
 {
-       int stack_start, top, index;
-       int num_values, used_for_temp, age;
-       jit_value_t value1, value2;
+       _jit_regdesc_t *desc;
+       int src_reg, dst_reg;
 
 #ifdef JIT_REG_DEBUG
-       printf("exch_stack_top(reg = %d, pop = %d)\n", reg, pop);
+       printf("move_input_value(%d)\n", index);
 #endif
 
-       if(!IS_STACK_REG(reg))
+       desc = &regs->descs[index];
+       if(!desc->value || desc->duplicate || !desc->value->in_register)
+       {
+               return;
+       }
+       if(!IS_STACK_REG(desc->value->reg))
        {
                return;
        }
 
-       /* Find the top of the stack. */
-       stack_start = get_stack_start(reg);
-       top = get_stack_top(gen, stack_start);
-
-       if(pop)
+       if(desc->copy)
        {
-               /* Generate move/pop-top instruction. */
-               _jit_gen_move_top(gen, reg);
-               remap_stack_down(gen, stack_start, top);
+               src_reg = desc->stack_reg;
+               if(src_reg < 0)
+               {
+                       return;
+               }
        }
        else
        {
-               /* Generate exchange instruction. */
-               _jit_gen_exch_top(gen, reg);
+               src_reg = desc->value->reg;
        }
 
-       /* Update information about the contents of the registers.  */
-       for(index = 0;
-           index < gen->contents[reg].num_values || index < 
gen->contents[top].num_values;
-           index++)
+       if(desc->reg < gen->reg_stack_top)
        {
-               value1 = (index < gen->contents[top].num_values
-                         ? gen->contents[top].values[index] : 0);
-               value2 = (index < gen->contents[reg].num_values
-                         ? gen->contents[reg].values[index] : 0);
-
-               if(value1)
+               dst_reg = desc->reg;
+       }
+       else
                {
-                       value1->reg = reg;
+               dst_reg = gen->reg_stack_top - 1;
                }
-               gen->contents[reg].values[index] = value1;
 
-               if(pop)
+       if(src_reg != dst_reg)
                {
-                       if(value2)
+               if(src_reg != (gen->reg_stack_top - 1))
                        {
-                               value2->reg = -1;
-                       }
-                       gen->contents[top].values[index] = 0;
+                       exch_stack_top(gen, src_reg, 0);
                }
-               else
-               {
-                       if(value2)
+               if(dst_reg != (gen->reg_stack_top - 1))
                        {
-                               value2->reg = top;
+                       exch_stack_top(gen, dst_reg, 0);
                        }
-                       gen->contents[top].values[index] = value2;
                }
+}
+#endif
+
+static void
+abort_input_value(jit_gencode_t gen, _jit_regs_t *regs, int index)
+{
+       _jit_regdesc_t *desc;
+       int reg, other_reg;
+
+#ifdef JIT_REG_DEBUG
+       printf("abort_input_value(%d)\n", index);
+#endif
+
+       desc = &regs->descs[index];
+       if(!desc->value || desc->duplicate)
+       {
+               return;
        }
 
-       if(pop)
+       if(desc->load && desc->value->in_register)
        {
-               num_values = 0;
-               used_for_temp = 0;
-               age = 0;
+               reg = desc->value->reg;
+               if(gen->contents[reg].is_long_start)
+               {
+                       other_reg = OTHER_REG(reg);
        }
        else
        {
-               num_values = gen->contents[reg].num_values;
-               used_for_temp = gen->contents[reg].used_for_temp;
-               age = gen->contents[reg].age;
+                       other_reg = -1;
+               }
+               unbind_value(gen, desc->value, reg, other_reg);
+#ifdef JIT_REG_STACK
+               if(IS_STACK_REG(reg))
+               {
+                       --(gen->reg_stack_top);
+               }
+#endif
        }
-       gen->contents[reg].num_values = gen->contents[top].num_values;
-       gen->contents[reg].used_for_temp = gen->contents[top].used_for_temp;
-       gen->contents[reg].age = gen->contents[top].age;
-       gen->contents[top].num_values = num_values;
-       gen->contents[top].used_for_temp = used_for_temp;
-       gen->contents[top].age = age;
 }
 
-/*
- * Drop value from register.
- */
 static void
-free_value(jit_gencode_t gen, jit_value_t value, int reg, int other_reg)
+commit_input_value(jit_gencode_t gen, _jit_regs_t *regs, int index)
 {
+       _jit_regdesc_t *desc;
+       int reg, other_reg;
+
 #ifdef JIT_REG_DEBUG
-       printf("free_value(value = ");
-       jit_dump_value(stdout, jit_value_get_function(value), value, 0);
-       printf(", reg = %d, other_reg = %d)\n", reg, other_reg);
+       printf("commit_input_value(%d)\n", index);
 #endif
 
-       /* Never free global registers. */
-       if(value->has_global_register && value->global_reg == reg)
+       desc = &regs->descs[index];
+       if(!desc->value || desc->duplicate)
+       {
+               return;
+       }
+
+       if(desc->copy)
+       {
+#ifdef JIT_REG_STACK
+               if(IS_STACK_REG(desc->reg))
+               {
+                       --(gen->reg_stack_top);
+               }
+#endif
+               gen->contents[desc->reg].used_for_temp = 0;
+               if(desc->other_reg >= 0)
        {
-               return;
+                       gen->contents[desc->other_reg].used_for_temp = 0;
+               }
        }
 
-       /* Free stack register. */
-       if(IS_STACK_REG(reg) && gen->contents[reg].num_values == 1)
+       if(desc->kill && desc->value->in_register)
        {
-               exch_stack_top(gen, reg, 1);
+               reg = desc->value->reg;
+               if(gen->contents[reg].is_long_start)
+               {
+                       other_reg = OTHER_REG(reg);
+               }
+               else
+               {
+                       other_reg = -1;
+               }
+               unbind_value(gen, desc->value, reg, other_reg);
+#ifdef JIT_REG_STACK
+               if(IS_STACK_REG(reg))
+               {
+                       --(gen->reg_stack_top);
+               }
+#endif
        }
 
-       unbind_value(gen, value, reg, other_reg);
+#ifdef JIT_REG_DEBUG
+       printf("value = ");
+       jit_dump_value(stdout, jit_value_get_function(desc->value), 
desc->value, 0);
+       printf("\n");
+       printf("value->in_register = %d\n", desc->value->in_register);
+       printf("value->reg = %d\n", desc->value->reg);
+       printf("value->in_global_register = %d\n", 
desc->value->in_global_register);
+       printf("value->global_reg = %d\n", desc->value->global_reg);
+       printf("value->in_frame = %d\n", desc->value->in_frame);
+#endif
 }
 
-/*
- * Save the value from the register into its frame position and optionally 
free it.
- * If the value is already in the frame or is a constant then it is not saved 
but
- * the free option still applies to them.
- */
 static void
-save_value(jit_gencode_t gen, jit_value_t value, int reg, int other_reg, int 
free)
+commit_output_value(jit_gencode_t gen, _jit_regs_t *regs)
 {
-       int stack_start, top;
+       _jit_regdesc_t *desc;
 
 #ifdef JIT_REG_DEBUG
-       printf("save_value(value = ");
-       jit_dump_value(stdout, jit_value_get_function(value), value, 0);
-       printf(", reg = %d, other_reg = %d)\n", reg, other_reg);
+       printf("commit_output_value()\n");
 #endif
-       /* First take care of values that reside in global registers. */
-       if(value->has_global_register)
-       {
-               /* Never free global registers. */
-               if(value->global_reg == reg)
+
+       desc = &regs->descs[0];
+       if(!desc->value)
                {
                        return;
                }
 
-               if(!value->in_global_register)
+#ifdef JIT_REG_STACK
+       if(IS_STACK_REG(desc->reg))
                {
-                       _jit_gen_spill_reg(gen, reg, other_reg, value);
-                       value->in_global_register = 1;
+               ++(gen->reg_stack_top);
                }
-               if(free)
+#endif
+       bind_value(gen, desc->value, desc->reg, desc->other_reg, 0);
+
+       if(!desc->used)
                {
-                       unbind_value(gen, value, reg, other_reg);
+               if(desc->live)
+               {
+                       save_value(gen, desc->value, desc->reg, 
desc->other_reg, 1);
                }
-               return;
+               else
+               {
+                       free_value(gen, desc->value, desc->reg, 
desc->other_reg, 0);
+               }
+       }
+       else if(desc->kill)
+       {
+               save_value(gen, desc->value, desc->reg, desc->other_reg, 1);
        }
 
-       /* Take care of constants and values that are already in frame. */
-       if(value->is_constant || value->in_frame)
+#ifdef JIT_REG_DEBUG
+       printf("value = ");
+       jit_dump_value(stdout, jit_value_get_function(desc->value), 
desc->value, 0);
+       printf("\n");
+       printf("value->in_register = %d\n", desc->value->in_register);
+       printf("value->reg = %d\n", desc->value->reg);
+       printf("value->in_global_register = %d\n", 
desc->value->in_global_register);
+       printf("value->global_reg = %d\n", desc->value->global_reg);
+       printf("value->in_frame = %d\n", desc->value->in_frame);
+#endif
+}
+
+/*@
+ * @deftypefun void _jit_regs_lookup (char *name)
+ * Get the pseudo register by its name.
+ * @end deftypefun
address@hidden/
+int
+_jit_regs_lookup(char *name)
+{
+       int reg;
+       if(name)
        {
-               if(free)
+               for(reg = 0; reg < JIT_NUM_REGS; reg++)
+               {
+                       if(strcmp(_jit_reg_info[reg].name, name) == 0)
                {
-                       free_value(gen, value, reg, other_reg);
+                               return reg;
+                       }
                }
-               return;
        }
+       return -1;
+}
 
-       /* Now really save the value into frame. */
-       if(IS_STACK_REG(reg))
+/*@
+ * @deftypefun int _jit_regs_needs_long_pair (jit_type_t type)
+ * Determine if a type requires a long register pair.
+ * @end deftypefun
address@hidden/
+int _jit_regs_needs_long_pair(jit_type_t type)
+{
+#if defined(JIT_NATIVE_INT32) && !defined(JIT_BACKEND_INTERP)
+       type = jit_type_normalize(type);
+       if(type)
        {
-               /* Find the top of the stack. */
-               stack_start = get_stack_start(reg);
-               top = get_stack_top(gen, stack_start);
-
-               /* Move the value on the stack top if it is already not there. 
*/
-               if(top != reg)
+               if(type->kind == JIT_TYPE_LONG || type->kind == JIT_TYPE_ULONG)
                {
-                       exch_stack_top(gen, reg, 0);
+                       return 1;
+               }
                }
+       return 0;
+#else
+       /* We don't register pairs on 64-bit platforms or the interpreter */
+       return 0;
+#endif
+}
 
-               if(free && gen->contents[top].num_values == 1)
+/*@
+ * @deftypefun int _jit_regs_get_cpu (jit_gencode_t gen, int reg, int 
*other_reg)
+ * Get the CPU register that corresponds to a pseudo register.
+ * "other_reg" will be set to the other register in a pair,
+ * or -1 if the register is not part of a pair.
+ * @end deftypefun
address@hidden/
+int _jit_regs_get_cpu(jit_gencode_t gen, int reg, int *other_reg)
+{
+       int cpu_reg, other;
+
+#ifdef JIT_REG_STACK
+       if(IS_STACK_REG(reg))
                {
-                       _jit_gen_spill_top(gen, top, value, 1);
-                       remap_stack_down(gen, stack_start, top);
+               reg = gen->reg_stack_top - reg;
+               cpu_reg = _jit_reg_info[reg].cpu_reg;
+               other = -1;
                }
                else
+#endif
                {
-                       _jit_gen_spill_top(gen, top, value, 0);
-               }
+               cpu_reg = _jit_reg_info[reg].cpu_reg;
+               if(gen->contents[reg].is_long_start)
+               {
+                       other = _jit_reg_info[reg].other_reg;
+                       other = _jit_reg_info[other].cpu_reg;
        }
        else
        {
-               _jit_gen_spill_reg(gen, reg, other_reg, value);
+                       other = -1;
        }
-
-       if(free)
+       }
+       if(other_reg)
        {
-               unbind_value(gen, value, reg, other_reg);
+               *other_reg = other;
        }
-       value->in_frame = 1;
+       return cpu_reg;
 }
 
-/*
- * Spill regular (non-stack) register.
- */
-static void
-spill_reg(jit_gencode_t gen, _jit_regs_t *regs, int reg)
+/*@
+ * @deftypefun void _jit_regs_alloc_global (jit_gencode_t gen, jit_function_t 
func)
+ * Perform global register allocation on the values in @code{func}.
+ * This is called during function compilation just after variable
+ * liveness has been computed.
+ * @end deftypefun
address@hidden/
+void _jit_regs_alloc_global(jit_gencode_t gen, jit_function_t func)
 {
-       int other_reg, index, usage;
-       jit_value_t value;
-
-#ifdef JIT_REG_DEBUG
-       printf("spill_reg(reg = %d)\n", reg);
-#endif
+#if JIT_NUM_GLOBAL_REGS != 0
+       jit_value_t candidates[JIT_NUM_GLOBAL_REGS];
+       int num_candidates = 0;
+       int index, reg, posn, num;
+       jit_pool_block_t block;
+       jit_value_t value, temp;
 
-       /* 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;
-               reg = get_long_pair_start(reg);
-       }
-       else
+       /* If the function has a "try" block, then don't do global allocation
+          as the "longjmp" for exception throws will wipe out global registers 
*/
+       if(func->has_try)
        {
-               other_reg = -1;
+               return;
        }
 
-       /* Spill register contents in two passes. First free values that
-          do not reqiure spilling then spill those that do. This approach
-          is only useful in case a stack register contains both kinds of
-          values and the last value is one that does not require spilling.
-          This way we may save one free instruction. */
-       if(IS_STACK_REG(reg))
+       /* If the current function involves a tail call, then we don't do
+          global register allocation and we also prevent the code generator
+          from using any of the callee-saved registers.  This simplifies
+          tail calls, which don't have to worry about restoring such registers 
*/
+       if(func->builder->has_tail_call)
        {
-               for(index = gen->contents[reg].num_values - 1; index >= 0; 
--index)
+               for(reg = 0; reg < JIT_NUM_REGS; ++reg)
                {
-                       value = gen->contents[reg].values[index];
-                       usage = value_usage(regs, value);
-                       if((usage & VALUE_INPUT) == 0
-                          && ((usage & VALUE_DEAD) != 0 || value->in_frame))
+                       if((_jit_reg_info[reg].flags &
+                                       (JIT_REG_FIXED | JIT_REG_CALL_USED)) == 
0)
                        {
-                               free_value(gen, value, reg, other_reg);
+                               jit_reg_set_used(gen->permanent, reg);
                        }
                }
+               return;
        }
-       for(index = gen->contents[reg].num_values - 1; index >= 0; --index)
+
+       /* Scan all values within the function, looking for the most used.
+          We will replace this with a better allocation strategy later */
+       block = func->builder->value_pool.blocks;
+       num = (int)(func->builder->value_pool.elems_per_block);
+       while(block != 0)
        {
-               value = gen->contents[reg].values[index];
-               usage = value_usage(regs, value);
-               if((usage & VALUE_DEAD) == 0)
+               if(!(block->next))
                {
-                       if((usage & VALUE_INPUT) == 0)
+                       num = (int)(func->builder->value_pool.elems_in_last);
+               }
+               for(posn = 0; posn < num; ++posn)
                        {
-                               save_value(gen, value, reg, other_reg, 1);
+                       value = (jit_value_t)(block->data + posn *
+                                                                 sizeof(struct 
_jit_value));
+                       if(value->global_candidate && value->usage_count >= 
JIT_MIN_USED &&
+                          !(value->is_addressable) && !(value->is_volatile))
+                       {
+                               /* Insert this candidate into the list, ordered 
on count */
+                               index = 0;
+                               while(index < num_candidates &&
+                                     value->usage_count <= 
candidates[index]->usage_count)
+                               {
+                                       ++index;
+                               }
+                               while(index < num_candidates)
+                               {
+                                       temp = candidates[index];
+                                       candidates[index] = value;
+                                       value = temp;
+                                       ++index;
                        }
-                       else
+                               if(index < JIT_NUM_GLOBAL_REGS)
                        {
-                               save_value(gen, value, reg, other_reg, 0);
+                                       candidates[num_candidates++] = value;
                        }
                }
-               else
+               }
+               block = block->next;
+       }
+
+       /* Allocate registers to the candidates.  We allocate from the top-most
+          register in the allocation order, because some architectures like
+          PPC require global registers to be saved top-down for efficiency */
+       reg = JIT_NUM_REGS - 1;
+       for(index = 0; index < num_candidates; ++index)
                {
-                       if((usage & VALUE_INPUT) == 0)
+               while(reg >= 0 && (_jit_reg_info[reg].flags & JIT_REG_GLOBAL) 
== 0)
                        {
-                               free_value(gen, value, reg, other_reg);
-                       }
+                       --reg;
                }
+               candidates[index]->has_global_register = 1;
+               candidates[index]->global_reg = (short)reg;
+               jit_reg_set_used(gen->touched, reg);
+               jit_reg_set_used(gen->permanent, reg);
+               --reg;
        }
+
+#endif
 }
 
-static void
-update_age(jit_gencode_t gen, _jit_regdesc_t *desc)
+/*@
+ * @deftypefun void _jit_regs_init_for_block (jit_gencode_t gen)
+ * Initialize the register allocation state for a new block.
+ * @end deftypefun
address@hidden/
+void _jit_regs_init_for_block(jit_gencode_t gen)
 {
-       int reg, other_reg;
-
-       reg = desc->value->reg;
-       if(gen->contents[reg].is_long_start)
+       int reg;
+       gen->current_age = 1;
+       for(reg = 0; reg < JIT_NUM_REGS; ++reg)
        {
-               other_reg = OTHER_REG(reg);
-       }
-       else
+               /* Clear everything except permanent and fixed registers */
+               if(!jit_reg_is_used(gen->permanent, reg) &&
+                  (_jit_reg_info[reg].flags & JIT_REG_FIXED) == 0)
        {
-               other_reg = -1;
+                       gen->contents[reg].num_values = 0;
+                       gen->contents[reg].is_long_start = 0;
+                       gen->contents[reg].is_long_end = 0;
+                       gen->contents[reg].age = 0;
+                       gen->contents[reg].used_for_temp = 0;
        }
-
-       gen->contents[reg].age = gen->current_age;
-       if(other_reg >= 0)
-       {
-               gen->contents[other_reg].age = gen->current_age;
+#ifdef JIT_REG_STACK
+               gen->reg_stack_top = JIT_REG_STACK_START;
+#endif
        }
-       ++(gen->current_age);
+       gen->inhibit = jit_regused_init;
 }
 
-static void
-save_input_value(jit_gencode_t gen, _jit_regs_t *regs, int index)
+/*@
+ * @deftypefun void _jit_regs_spill_all (jit_gencode_t gen)
+ * Spill all of the temporary registers to memory locations.
+ * Normally used at the end of a block, but may also be used in
+ * situations where a value must be in a certain register and
+ * it is too hard to swap things around to put it there.
+ * @end deftypefun
address@hidden/
+void
+_jit_regs_spill_all(jit_gencode_t gen)
 {
-       _jit_regdesc_t *desc;
-       int reg, other_reg;
+       int reg;
 
 #ifdef JIT_REG_DEBUG
-       printf("save_input_value(%d)\n", index);
+       printf("enter _jit_regs_spill_all\n");
 #endif
 
-       desc = &regs->descs[index];
-       if(!(desc->value && desc->value->in_register && desc->save))
+       for(reg = 0; reg < JIT_NUM_REGS; reg++)
        {
-               return;
+               /* Skip this register if it is permanent or fixed */
+               if(jit_reg_is_used(gen->permanent, reg) ||
+                  (_jit_reg_info[reg].flags & JIT_REG_FIXED) != 0)
+               {
+                       continue;
        }
 
-       reg = desc->value->reg;
-       if(gen->contents[reg].is_long_start)
+               /* 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 */
+#ifdef JIT_REG_STACK
+               if(IS_STACK_REG(reg))
        {
-               other_reg = OTHER_REG(reg);
-       }
-       else
+                       if(gen->reg_stack_top > JIT_REG_STACK_START)
        {
-               other_reg = -1;
+                               spill_register(gen, gen->reg_stack_top - 1);
        }
-
-       if(desc->thrash)
-       {
-               save_value(gen, desc->value, reg, other_reg, 1);
        }
        else
+#endif
        {
-               save_value(gen, desc->value, reg, other_reg, 0);
+                       spill_register(gen, reg);
+               }
        }
-}
-
-static void
-free_output_value(jit_gencode_t gen, _jit_regs_t *regs)
-{
-       _jit_regdesc_t *desc;
-       int reg, other_reg;
 
 #ifdef JIT_REG_DEBUG
-       printf("free_output_value()\n");
+       printf("leave _jit_regs_spill_all\n");
 #endif
+}
 
-       desc = &regs->descs[0];
-       if(!(desc->value && desc->value->in_register))
-       {
-               return;
-       }
-       if(desc->value == regs->descs[1].value || desc->value == 
regs->descs[2].value)
-       {
-               return;
-       }
+/*@
+ * @deftypefun void _jit_regs_set_incoming (jit_gencode_t gen, int reg, 
jit_value_t value)
+ * Set pseudo register @code{reg} to record that it currently holds the
+ * contents of @code{value}.  If the register was previously in use,
+ * then spill its value first.
+ * @end deftypefun
address@hidden/
+void
+_jit_regs_set_incoming(jit_gencode_t gen, int reg, jit_value_t value)
+{
+       int other_reg;
 
-       reg = desc->value->reg;
-       if(gen->contents[reg].is_long_start)
+       /* Find the other register in a long pair */
+       if(_jit_regs_needs_long_pair(value->type))
        {
                other_reg = OTHER_REG(reg);
        }
@@ -3674,160 +2644,114 @@
                other_reg = -1;
        }
 
-       free_value(gen, desc->value, reg, other_reg);
-}
-
-static void
-load_input_value(jit_gencode_t gen, _jit_regs_t *regs, int index)
-{
-       _jit_regdesc_t *desc;
-
-#ifdef JIT_REG_DEBUG
-       printf("load_input_value(%d)\n", index);
-#endif
-
-       desc = &regs->descs[index];
-       if(!desc->value || desc->duplicate)
-       {
-               return;
-       }
-
-       if(desc->value->has_global_register)
-       {
-               if(desc->value->in_global_register && desc->value->global_reg 
== desc->reg)
-               {
-                       return;
-               }
-               if(desc->value->in_register && desc->value->reg == desc->reg)
-               {
-                       update_age(gen, desc);
-                       return;
-               }
-               _jit_gen_load_value(gen, desc->reg, desc->other_reg, 
desc->value);
-       }
-       else if(desc->value->in_register)
-       {
-               if(desc->value->reg == desc->reg)
-               {
-                       update_age(gen, desc);
-                       if(IS_STACK_REG(desc->reg))
+       /* Eject any values that are currently in the register */
+       spill_register(gen, reg);
+       if(other_reg >= 0)
                        {
-                               desc->stack_reg = desc->reg;
-                       }
-                       return;
+               spill_register(gen, other_reg);
                }
 
-               if(IS_STACK_REG(desc->reg))
-               {
-                       desc->stack_reg = ++(regs->current_stack_top);
-                       _jit_gen_load_value(gen, desc->stack_reg, -1, 
desc->value);
-                       bind_temporary(gen, desc->stack_reg, -1);
-                       remap_stack_up(gen, regs->stack_start, desc->stack_reg);
-               }
-               else
-               {
-                       _jit_gen_load_value(gen, desc->reg, desc->other_reg, 
desc->value);
-                       bind_temporary(gen, desc->reg, desc->other_reg);
-               }
-       }
-       else
-       {
-               if(IS_STACK_REG(desc->reg))
-               {
-                       desc->stack_reg = ++(regs->current_stack_top);
-                       _jit_gen_load_value(gen, desc->stack_reg, -1, 
desc->value);
-                       bind_value(gen, desc->value, desc->stack_reg, -1, 1);
-                       remap_stack_up(gen, regs->stack_start, desc->stack_reg);
-               }
-               else
+       /* Record that the value is in "reg", but not in the frame */
+#ifdef JIT_REG_STACK
+       if(IS_STACK_REG(reg))
                {
-                       _jit_gen_load_value(gen, desc->reg, desc->other_reg, 
desc->value);
-                       bind_value(gen, desc->value, desc->reg, 
desc->other_reg, 1);
-               }
+               ++(gen->reg_stack_top);
        }
+#endif
+       bind_value(gen, value, reg, other_reg, 0);
 }
 
-static void
-move_input_value(jit_gencode_t gen, _jit_regs_t *regs, int index)
+/*@
+ * @deftypefun void _jit_regs_set_outgoing (jit_gencode_t gen, int reg, 
jit_value_t value)
+ * Load the contents of @code{value} into pseudo register @code{reg},
+ * spilling out the current contents.  This is used to set up outgoing
+ * parameters for a function call.
+ * @end deftypefun
address@hidden/
+void
+_jit_regs_set_outgoing(jit_gencode_t gen, int reg, jit_value_t value)
 {
-       _jit_regdesc_t *desc;
-       int src_reg, dst_reg;
+       int other_reg;
 
-#ifdef JIT_REG_DEBUG
-       printf("move_input_value(%d)\n", index);
-#endif
+#ifdef JIT_BACKEND_X86
+       jit_type_t type;
 
-       desc = &regs->descs[index];
-       if(!desc->value || desc->duplicate || !desc->value->in_register)
-       {
-               return;
-       }
-       if(!IS_STACK_REG(desc->value->reg))
-       {
-               return;
-       }
+       other_reg = -1;
 
-       if(desc->copy)
+       type = jit_type_normalize(value->type);
+       if(type)
        {
-               src_reg = desc->stack_reg;
-               if(src_reg < 0)
+               /* We might need to put float values in register pairs under 
x86 */
+               if(type->kind == JIT_TYPE_LONG || type->kind == JIT_TYPE_ULONG 
||
+                  type->kind == JIT_TYPE_FLOAT64 || type->kind == 
JIT_TYPE_NFLOAT)
                {
-                       return;
+                       /* Long values in outgoing registers must be in ECX:EDX,
+                          not in the ordinary register pairing of ECX:EBX */
+                       other_reg = 2;
+
+                       /* Force the value out of whatever register it is 
already in */
+                       _jit_regs_force_out(gen, value, 0);
                }
        }
-       else
+#else
+       if(_jit_regs_needs_long_pair(value->type))
        {
-               src_reg = desc->value->reg;
+               other_reg = OTHER_REG(reg);
        }
-
-       if(desc->reg <= regs->current_stack_top)
+       else
        {
-               dst_reg = desc->reg;
+               other_reg = -1;
        }
-       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)
+#endif
+       if(value->in_register && value->reg == reg)
        {
-               dst_reg = regs->current_stack_top - 1;
-       }
-       else
+               /* The value is already in the register, but we may need to 
spill
+                  if the frame copy is not up to date with the register */
+               if(!(value->in_global_register || value->in_frame))
        {
-               dst_reg = regs->current_stack_top;
+                       save_value(gen, value, reg, other_reg, 0);
        }
 
-       if(src_reg != dst_reg)
+               /* The value is no longer "really" in the register.  A copy is
+                  left behind, but the value itself reverts to the frame copy
+                  as we are about to kill the registers in a function call */
+               free_value(gen, value, reg, other_reg, 1);
+       }
+       else
        {
-               if(src_reg != regs->current_stack_top)
+               /* Reload the value into the specified register */
+               spill_register(gen, reg);
+               if(other_reg >= 0)
                {
-                       exch_stack_top(gen, src_reg, 0);
+                       spill_register(gen, other_reg);
                }
-               if(dst_reg != regs->current_stack_top)
+
+               _jit_gen_load_value(gen, reg, other_reg, value);
+
+               jit_reg_set_used(gen->inhibit, reg);
+               if(other_reg > 0)
                {
-                       exch_stack_top(gen, dst_reg, 0);
+                       jit_reg_set_used(gen->inhibit, other_reg);
                }
        }
 }
 
-static void
-abort_input_value(jit_gencode_t gen, _jit_regs_t *regs, int index)
+/*@
+ * @deftypefun void _jit_regs_force_out (jit_gencode_t gen, jit_value_t value, 
int is_dest)
+ * If @code{value} is currently in a register, then force its value out
+ * into the stack frame.  The @code{is_dest} flag indicates that the value
+ * will be a destination, so we don't care about the original value.
+ * @end deftypefun
address@hidden/
+void _jit_regs_force_out(jit_gencode_t gen, jit_value_t value, int is_dest)
 {
-       _jit_regdesc_t *desc;
        int reg, other_reg;
-
-#ifdef JIT_REG_DEBUG
-       printf("abort_input_value(%d)\n", index);
-#endif
-
-       desc = &regs->descs[index];
-       if(!desc->value || desc->duplicate)
+       if(value->in_register)
        {
-               return;
-       }
+               reg = value->reg;
 
-       if(desc->load && desc->value->in_register)
-       {
-               reg = desc->value->reg;
-               if(gen->contents[reg].is_long_start)
+               /* Find the other register in a long pair */
+               if(_jit_regs_needs_long_pair(value->type))
                {
                        other_reg = OTHER_REG(reg);
                }
@@ -3836,132 +2760,146 @@
                        other_reg = -1;
                }
 
-               if(IS_STACK_REG(reg))
+               if(is_dest)
                {
-                       unbind_value(gen, desc->value, reg, -1);
-                       remap_stack_down(gen, regs->stack_start, reg);
+                       free_value(gen, value, reg, other_reg, 0);
                }
                else
                {
-                       unbind_value(gen, desc->value, reg, other_reg);
+                       save_value(gen, value, reg, other_reg, 1);
                }
        }
 }
 
-static void
-commit_input_value(jit_gencode_t gen, _jit_regs_t *regs, int index)
+/*@
+ * @deftypefun int _jit_regs_load_value (jit_gencode_t gen, jit_value_t value, 
int destroy, int used_again)
+ * Load a value into any register that is suitable and return that register.
+ * If the value needs a long pair, then this will return the first register
+ * in the pair.  Returns -1 if the value will not fit into any register.
+ *
+ * If @code{destroy} is non-zero, then we are about to destroy the register,
+ * so the system must make sure that such destruction will not side-effect
+ * @code{value} or any of the other values currently in that register.
+ *
+ * If @code{used_again} is non-zero, then it indicates that the value is
+ * used again further down the block.
+ * @end deftypefun
address@hidden/
+int
+_jit_regs_load_value(jit_gencode_t gen, jit_value_t value, int destroy, int 
used_again)
 {
-       _jit_regdesc_t *desc;
+       int type, need_pair;
        int reg, other_reg;
+       int spill_cost;
+       int suitable_reg, suitable_other_reg;
+       int suitable_cost;
+       int suitable_age;
 
-#ifdef JIT_REG_DEBUG
-       printf("commit_input_value(%d)\n", index);
-#endif
-
-       desc = &regs->descs[index];
-       if(!desc->value || desc->duplicate)
+       /* If the value is in a global register, and we are not going
+          to destroy the value, then use the global register itself.
+          This will avoid a redundant register copy operation */
+       if(value->in_global_register && !destroy)
        {
-               return;
+               return value->global_reg;
        }
 
-       if(desc->copy)
+       need_pair = _jit_regs_needs_long_pair(value->type);
+
+       /* If the value is already in a register, then try to use that register 
*/
+       if(value->in_register && (!destroy || !used_again))
        {
-               if(IS_STACK_REG(desc->reg))
+               reg = value->reg;
+               if(!used_again)
+               {
+                       if(need_pair)
                {
-                       remap_stack_down(gen, regs->stack_start, desc->reg);
+                               other_reg = OTHER_REG(reg);
                }
-               gen->contents[desc->reg].used_for_temp = 0;
-               if(desc->other_reg >= 0)
+                       else
                {
-                       gen->contents[desc->other_reg].used_for_temp = 0;
+                               other_reg = -1;
+                       }
+                       free_value(gen, value, reg, other_reg, 1);
                }
+               return reg;
        }
 
-       if(desc->kill && desc->value->in_register)
+       type = get_register_type(value, need_pair);
+       if(!type)
        {
-               reg = desc->value->reg;
-               if(gen->contents[reg].is_long_start)
+               return 0;
+       }
+
+       suitable_reg = -1;
+       suitable_other_reg = -1;
+       suitable_cost = COST_TOO_MUCH;
+       suitable_age = -1;
+       for(reg = 0; reg < JIT_NUM_REGS; reg++)
                {
-                       other_reg = OTHER_REG(reg);
+               if((_jit_reg_info[reg].flags & type) == 0)
+               {
+                       continue;
                }
-               else
+               if(jit_reg_is_used(gen->inhibit, reg))
                {
-                       other_reg = -1;
+                       continue;
+               }
+               if(jit_reg_is_used(gen->permanent, reg))
+               {
+                       continue;
                }
 
-               if(IS_STACK_REG(reg))
+               if(need_pair)
+               {
+                       other_reg = OTHER_REG(reg);
+                       if(jit_reg_is_used(gen->inhibit, other_reg))
                {
-                       unbind_value(gen, desc->value, reg, -1);
-                       remap_stack_down(gen, regs->stack_start, reg);
+                               continue;
                }
-               else
+                       if(jit_reg_is_used(gen->permanent, other_reg))
                {
-                       unbind_value(gen, desc->value, reg, other_reg);
+                               continue;
                }
        }
+               else
+               {
+                       other_reg = -1;
+               }
 
-#ifdef JIT_REG_DEBUG
-       printf("value = ");
-       jit_dump_value(stdout, jit_value_get_function(desc->value), 
desc->value, 0);
-       printf("\n");
-       printf("value->in_register = %d\n", desc->value->in_register);
-       printf("value->reg = %d\n", desc->value->reg);
-       printf("value->in_global_register = %d\n", 
desc->value->in_global_register);
-       printf("value->global_reg = %d\n", desc->value->global_reg);
-       printf("value->in_frame = %d\n", desc->value->in_frame);
-#endif
-}
-
-static void
-commit_output_value(jit_gencode_t gen, _jit_regs_t *regs)
-{
-       _jit_regdesc_t *desc;
-
-#ifdef JIT_REG_DEBUG
-       printf("commit_output_value()\n");
-#endif
+               spill_cost = compute_spill_cost(gen, 0, reg, other_reg);
 
-       desc = &regs->descs[0];
-       if(!desc->value)
+               if(spill_cost < suitable_cost
+                  || (spill_cost == suitable_cost
+                      && spill_cost > 0 && gen->contents[reg].age < 
suitable_age))
        {
-               return;
+                       suitable_reg = reg;
+                       suitable_other_reg = other_reg;
+                       suitable_cost = spill_cost;
+                       suitable_age = gen->contents[reg].age;
+               }
        }
 
-       if(IS_STACK_REG(desc->reg))
+       if(suitable_reg >= 0)
        {
-               bind_value(gen, desc->value, desc->reg, -1, 0);
-               remap_stack_up(gen, regs->stack_start, desc->reg);
-       }
-       else
+               spill_register(gen, suitable_reg);
+               if(suitable_other_reg >= 0)
        {
-               bind_value(gen, desc->value, desc->reg, desc->other_reg, 0);
+                       spill_register(gen, suitable_other_reg);
        }
-       if(!desc->used)
-       {
-               if(desc->live)
+
+               _jit_gen_load_value(gen, suitable_reg, suitable_other_reg, 
value);
+
+               if(!destroy && !used_again)
                {
-                       save_value(gen, desc->value, desc->reg, 
desc->other_reg, 1);
+                       bind_value(gen, value, suitable_reg, 
suitable_other_reg, 1);
                }
                else
                {
-                       free_value(gen, desc->value, desc->reg, 
desc->other_reg);
+                       bind_temporary(gen, suitable_reg, suitable_other_reg);
                }
        }
-       else if(desc->kill)
-       {
-               save_value(gen, desc->value, desc->reg, desc->other_reg, 1);
-       }
 
-#ifdef JIT_REG_DEBUG
-       printf("value = ");
-       jit_dump_value(stdout, jit_value_get_function(desc->value), 
desc->value, 0);
-       printf("\n");
-       printf("value->in_register = %d\n", desc->value->in_register);
-       printf("value->reg = %d\n", desc->value->reg);
-       printf("value->in_global_register = %d\n", 
desc->value->in_global_register);
-       printf("value->global_reg = %d\n", desc->value->global_reg);
-       printf("value->in_frame = %d\n", desc->value->in_frame);
-#endif
+       return suitable_reg;
 }
 
 void
@@ -4016,8 +2954,6 @@
 
        regs->assigned = gen->inhibit;
 
-       regs->stack_start = -1;
-       regs->current_stack_top = 0;
        regs->wanted_stack_count = 0;
        regs->loaded_stack_count = 0;
 }
@@ -4291,14 +3227,13 @@
 int
 _jit_regs_gen(jit_gencode_t gen, _jit_regs_t *regs)
 {
-       int reg, stack_start, top;
+       int reg;
 
 #ifdef JIT_REG_DEBUG
        dump_regs(gen, "enter _jit_regs_gen");
 #endif
 
        /* Spill clobbered registers. */
-       stack_start = 0;
        for(reg = 0; reg < JIT_NUM_REGS; reg++)
        {
                if((_jit_reg_info[reg].flags & JIT_REG_FIXED))
@@ -4306,12 +3241,6 @@
                        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;
@@ -4332,40 +3261,46 @@
                        continue;
                }
 
+#ifdef JIT_REG_STACK
                /* 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 = get_stack_top(gen, stack_start);
-                       while(top > reg && jit_reg_is_used(regs->clobber, top))
+                       int top = gen->reg_stack_top - 1;
+
+                       /* spill top registers if there are any that needs to 
be */
+                       for(; top > reg && jit_reg_is_used(regs->clobber, top); 
top--)
                        {
-                               spill_reg(gen, regs, top);
-                               /* If one of the input values is on the top
-                                  spill_reg() will not pop it. */
+                               spill_clobbered_register(gen, regs, top);
+                               /* If an input value is on the top then it 
stays there
+                                  and the top does not change. */
                                if(gen->contents[top].num_values > 0)
                                {
                                        break;
                                }
-                               top = get_stack_top(gen, stack_start);
                        }
+                       /* If the top register was not spilled then exchange it 
with
+                          the current register. */
                        if(top > reg)
                        {
                                exch_stack_top(gen, reg, 0);
                        }
-                       if(top >= stack_start)
+                       /* Finally spill the register */
+                       if(top >= JIT_REG_STACK_START)
                        {
-                               spill_reg(gen, regs, top);
+                               spill_clobbered_register(gen, regs, top);
                        }
                }
                else
+#endif
                {
-                       spill_reg(gen, regs, reg);
+                       spill_clobbered_register(gen, regs, reg);
                }
        }
 
-       /* Save input values if necessary and free output value if it is in a 
register */
+       /* Save input values if necessary and free the output value if it is in 
a register */
        if(regs->ternary)
        {
                save_input_value(gen, regs, 0);
@@ -4377,44 +3312,25 @@
        save_input_value(gen, regs, 1);
        save_input_value(gen, regs, 2);
 
-       /* Adjust assignment of stack registers. */
+#ifdef JIT_REG_STACK
        if(regs->wanted_stack_count > 0)
        {
-               regs->current_stack_top = get_stack_top(gen, regs->stack_start);
-
+               /* Adjust assignment of stack registers. */
                adjust_assignment(gen, regs, 0);
                adjust_assignment(gen, regs, 1);
                adjust_assignment(gen, regs, 2);
 
                select_stack_order(gen, regs);
-       }
 
        /* Shuffle the values that are already on the register stack. */
-       if(regs->loaded_stack_count > 0)
-       {
-               if(regs->ternary)
-               {
-                       if(regs->descs[0].value && 
regs->descs[0].value->in_register)
-                       {
-                               move_input_value(gen, regs, 0);
-                               move_input_value(gen, regs, 1);
-                               move_input_value(gen, regs, 2);
-                       }
-                       else
-                       {
-                               move_input_value(gen, regs, 2);
-                               move_input_value(gen, regs, 1);
-                       }
-               }
-               else if(!regs->x87_arith)
+               if(regs->loaded_stack_count > 0 && !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)
+               if(regs->reverse_args)
        {
                load_input_value(gen, regs, 2);
                move_input_value(gen, regs, 2);
@@ -4433,6 +3349,18 @@
                load_input_value(gen, regs, 2);
                move_input_value(gen, regs, 2);
        }
+       }
+       else
+#endif
+       {
+               /* Load flat registers. */
+               if(regs->ternary)
+               {
+                       load_input_value(gen, regs, 0);
+               }
+               load_input_value(gen, regs, 1);
+               load_input_value(gen, regs, 2);
+       }
 
 #ifdef JIT_REG_DEBUG
        dump_regs(gen, "leave _jit_regs_gen");
@@ -4471,12 +3399,14 @@
        dump_regs(gen, "enter _jit_regs_commit");
 #endif
 
-       if(regs->x87_arith && regs->reverse_args)
+#ifdef JIT_REG_STACK
+       if(regs->reverse_args)
        {
                commit_input_value(gen, regs, 1);
                commit_input_value(gen, regs, 2);
        }
        else
+#endif
        {
                commit_input_value(gen, regs, 2);
                commit_input_value(gen, regs, 1);
@@ -4507,12 +3437,12 @@
 void
 _jit_regs_abort(jit_gencode_t gen, _jit_regs_t *regs)
 {
+       abort_input_value(gen, regs, 2);
+       abort_input_value(gen, regs, 1);
        if(regs->ternary)
        {
                abort_input_value(gen, regs, 0);
        }
-       abort_input_value(gen, regs, 1);
-       abort_input_value(gen, regs, 2);
 }
 
 unsigned char *
@@ -4559,25 +3489,3 @@
        gen->posn.ptr = inst;
        _jit_regs_commit(gen, regs);
 }
-
-/*@
- * @deftypefun void _jit_regs_lookup (char *name)
- * Get register by name.
- * @end deftypefun
address@hidden/
-int
-_jit_regs_lookup(char *name)
-{
-       int reg;
-       if(name)
-       {
-               for(reg = 0; reg < JIT_NUM_REGS; reg++)
-               {
-                       if(strcmp(_jit_reg_info[reg].name, name) == 0)
-                       {
-                               return reg;
-                       }
-               }
-       }
-       return -1;
-}

Index: jit/jit-reg-alloc.h
===================================================================
RCS file: /sources/dotgnu-pnet/libjit/jit/jit-reg-alloc.h,v
retrieving revision 1.18
retrieving revision 1.19
diff -u -b -r1.18 -r1.19
--- jit/jit-reg-alloc.h 9 Sep 2006 05:21:03 -0000       1.18
+++ jit/jit-reg-alloc.h 14 Sep 2006 06:27:08 -0000      1.19
@@ -27,43 +27,6 @@
 extern "C" {
 #endif
 
-void _jit_regs_init_for_block(jit_gencode_t gen);
-int _jit_regs_needs_long_pair(jit_type_t type);
-int _jit_regs_get_cpu(jit_gencode_t gen, int reg, int *other_reg);
-void _jit_regs_spill_all(jit_gencode_t gen);
-int _jit_regs_want_reg(jit_gencode_t gen, int reg, int for_long);
-void _jit_regs_free_reg(jit_gencode_t gen, int reg, int value_used);
-void _jit_regs_set_value
-       (jit_gencode_t gen, int reg, jit_value_t value, int still_in_frame);
-void _jit_regs_set_incoming(jit_gencode_t gen, int reg, jit_value_t value);
-void _jit_regs_set_outgoing(jit_gencode_t gen, int reg, jit_value_t value);
-int _jit_regs_is_top(jit_gencode_t gen, jit_value_t value);
-int _jit_regs_is_top_two
-       (jit_gencode_t gen, jit_value_t value1, jit_value_t value2);
-int _jit_regs_load_value
-       (jit_gencode_t gen, jit_value_t value, int destroy, int used_again);
-int _jit_regs_dest_value(jit_gencode_t gen, jit_value_t value);
-int _jit_regs_load_to_top
-       (jit_gencode_t gen, jit_value_t value, int used_again, int type_reg);
-int _jit_regs_load_to_top_two
-       (jit_gencode_t gen, jit_value_t value, jit_value_t value2,
-        int used_again1, int used_again2, int type_reg);
-void _jit_regs_load_to_top_three
-       (jit_gencode_t gen, jit_value_t value, jit_value_t value2,
-        jit_value_t value3, int used_again1, int used_again2,
-        int used_again3, int type_reg);
-int _jit_regs_num_used(jit_gencode_t gen, int type_reg);
-int _jit_regs_new_top(jit_gencode_t gen, jit_value_t value, int type_reg);
-void _jit_regs_force_out(jit_gencode_t gen, jit_value_t value, int is_dest);
-void _jit_regs_alloc_global(jit_gencode_t gen, jit_function_t func);
-void _jit_regs_get_reg_pair(jit_gencode_t gen, int not_this1, int not_this2,
-                           int not_this3, int *reg, int *reg2);
-
-
-/*
- * New Reg Alloc API
- */
-
 /*
  * The maximum number of values per instruction.
  */
@@ -140,6 +103,10 @@
  */
 typedef struct
 {
+       _jit_regdesc_t  descs[_JIT_REGS_VALUE_MAX];
+       _jit_scratch_t  scratch[_JIT_REGS_SCRATCH_MAX];
+       int             num_scratch;
+
        unsigned        clobber_all : 1;
        unsigned        clobber_stack : 1;
        unsigned        ternary : 1;
@@ -155,22 +122,33 @@
        unsigned        reverse_dest : 1;
        unsigned        reverse_args : 1;
 
-       _jit_regdesc_t  descs[_JIT_REGS_VALUE_MAX];
-       _jit_scratch_t  scratch[_JIT_REGS_SCRATCH_MAX];
-       int             num_scratch;
-
+       /* The input value index that is going to be overwritten
+          by the destination value. For ordinary binary and unary
+          opcodes it is equal to 1, for notes and three-address
+          opcodes it is equal to 0, and for some x87 instructions
+          it could be equal to 2.  */
        int             dest_input_index;
 
        jit_regused_t   assigned;
        jit_regused_t   clobber;
 
-       int             stack_start;
-       int             current_stack_top;
        int             wanted_stack_count;
        int             loaded_stack_count;
 
 } _jit_regs_t;
 
+int _jit_regs_lookup(char *name);
+int _jit_regs_needs_long_pair(jit_type_t type);
+int _jit_regs_get_cpu(jit_gencode_t gen, int reg, int *other_reg);
+
+void _jit_regs_alloc_global(jit_gencode_t gen, jit_function_t func);
+void _jit_regs_init_for_block(jit_gencode_t gen);
+void _jit_regs_spill_all(jit_gencode_t gen);
+void _jit_regs_set_incoming(jit_gencode_t gen, int reg, jit_value_t value);
+void _jit_regs_set_outgoing(jit_gencode_t gen, int reg, jit_value_t value);
+void _jit_regs_force_out(jit_gencode_t gen, jit_value_t value, int is_dest);
+int _jit_regs_load_value(jit_gencode_t gen, jit_value_t value, int destroy, 
int used_again);
+
 void _jit_regs_init(jit_gencode_t gen, _jit_regs_t *regs, int flags);
 void _jit_regs_init_dest(_jit_regs_t *regs, jit_insn_t insn, int flags);
 void _jit_regs_init_value1(_jit_regs_t *regs, jit_insn_t insn, int flags);
@@ -205,8 +183,6 @@
 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
 };
 #endif

Index: jit/jit-rules-x86.c
===================================================================
RCS file: /sources/dotgnu-pnet/libjit/jit/jit-rules-x86.c,v
retrieving revision 1.39
retrieving revision 1.40
diff -u -b -r1.39 -r1.40
--- jit/jit-rules-x86.c 30 Aug 2006 19:23:27 -0000      1.39
+++ jit/jit-rules-x86.c 14 Sep 2006 06:27:08 -0000      1.40
@@ -435,140 +435,6 @@
 }
 
 /*
- * Load a small structure from a pointer into registers.
- */
-static unsigned char *load_small_struct
-       (unsigned char *inst, int reg, int other_reg,
-        int base_reg, jit_nint offset, jit_nint size, int save_temp)
-{
-       int temp_reg;
-       switch(size)
-       {
-               case 1:
-               {
-                       x86_widen_membase(inst, reg, base_reg, offset, 0, 0);
-               }
-               break;
-
-               case 2:
-               {
-                       x86_widen_membase(inst, reg, base_reg, offset, 0, 1);
-               }
-               break;
-
-               case 3:
-               {
-                       temp_reg = get_temp_reg(reg, -1, base_reg);
-                       if(save_temp || temp_reg >= X86_EBX)
-                       {
-                               x86_push_reg(inst, temp_reg);
-                       }
-                       x86_widen_membase(inst, temp_reg, base_reg, offset, 0, 
1);
-                       x86_widen_membase(inst, reg, base_reg, offset + 2, 0, 
0);
-                       x86_shift_reg_imm(inst, X86_SHL, reg, 16);
-                       x86_alu_reg_reg(inst, X86_OR, reg, temp_reg);
-                       if(save_temp || temp_reg >= X86_EBX)
-                       {
-                               x86_pop_reg(inst, temp_reg);
-                       }
-               }
-               break;
-
-               case 4:
-               {
-                       x86_mov_reg_membase(inst, reg, base_reg, offset, 4);
-               }
-               break;
-
-               case 5:
-               {
-                       if(reg != base_reg)
-                       {
-                               x86_mov_reg_membase(inst, reg, base_reg, 
offset, 4);
-                               x86_widen_membase(inst, other_reg, base_reg, 
offset + 4, 0, 0);
-                       }
-                       else
-                       {
-                               x86_widen_membase(inst, other_reg, base_reg, 
offset + 4, 0, 0);
-                               x86_mov_reg_membase(inst, reg, base_reg, 
offset, 4);
-                       }
-               }
-               break;
-
-               case 6:
-               {
-                       if(reg != base_reg)
-                       {
-                               x86_mov_reg_membase(inst, reg, base_reg, 
offset, 4);
-                               x86_widen_membase(inst, other_reg, base_reg, 
offset + 4, 0, 1);
-                       }
-                       else
-                       {
-                               x86_widen_membase(inst, other_reg, base_reg, 
offset + 4, 0, 1);
-                               x86_mov_reg_membase(inst, reg, base_reg, 
offset, 4);
-                       }
-               }
-               break;
-
-               case 7:
-               {
-                       temp_reg = get_temp_reg(reg, other_reg, base_reg);
-                       if(save_temp || temp_reg >= X86_EBX)
-                       {
-                               x86_push_reg(inst, temp_reg);
-                       }
-                       if(reg != base_reg && other_reg != base_reg)
-                       {
-                               x86_mov_reg_membase(inst, reg, base_reg, 
offset, 4);
-                               x86_widen_membase(inst, other_reg, base_reg, 
offset + 4, 0, 1);
-                               x86_widen_membase(inst, temp_reg, base_reg, 
offset + 6, 0, 0);
-                               x86_shift_reg_imm(inst, X86_SHL, temp_reg, 16);
-                               x86_alu_reg_reg(inst, X86_OR, other_reg, 
temp_reg);
-                       }
-                       else if(reg != base_reg)
-                       {
-                               /* other_reg == base_reg */
-                               x86_mov_reg_membase(inst, reg, base_reg, 
offset, 4);
-                               x86_widen_membase(inst, temp_reg, base_reg, 
offset + 6, 0, 0);
-                               x86_widen_membase(inst, other_reg, base_reg, 
offset + 4, 0, 1);
-                               x86_shift_reg_imm(inst, X86_SHL, temp_reg, 16);
-                               x86_alu_reg_reg(inst, X86_OR, other_reg, 
temp_reg);
-                       }
-                       else
-                       {
-                               /* reg == base_reg */
-                               x86_widen_membase(inst, other_reg, base_reg, 
offset + 4, 0, 1);
-                               x86_widen_membase(inst, temp_reg, base_reg, 
offset + 6, 0, 0);
-                               x86_shift_reg_imm(inst, X86_SHL, temp_reg, 16);
-                               x86_alu_reg_reg(inst, X86_OR, other_reg, 
temp_reg);
-                               x86_mov_reg_membase(inst, reg, base_reg, 
offset, 4);
-                       }
-                       if(save_temp || temp_reg >= X86_EBX)
-                       {
-                               x86_pop_reg(inst, temp_reg);
-                       }
-               }
-               break;
-
-               case 8:
-               {
-                       if(reg != base_reg)
-                       {
-                               x86_mov_reg_membase(inst, reg, base_reg, 
offset, 4);
-                               x86_mov_reg_membase(inst, other_reg, base_reg, 
offset + 4, 4);
-                       }
-                       else
-                       {
-                               x86_mov_reg_membase(inst, other_reg, base_reg, 
offset + 4, 4);
-                               x86_mov_reg_membase(inst, reg, base_reg, 
offset, 4);
-                       }
-               }
-               break;
-       }
-       return inst;
-}
-
-/*
  * Store a byte value to a membase address.
  */
 static unsigned char *mov_membase_reg_byte
@@ -769,8 +635,7 @@
 static int
 fp_stack_index(jit_gencode_t gen, int reg)
 {
-       int top = gen->stack_map[X86_REG_ST0];
-       return top - reg;
+       return gen->reg_stack_top - reg - 1;
 }
 
 void

Index: jit/jit-rules-x86.h
===================================================================
RCS file: /sources/dotgnu-pnet/libjit/jit/jit-rules-x86.h,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -b -r1.5 -r1.6
--- jit/jit-rules-x86.h 24 Jun 2004 04:11:46 -0000      1.5
+++ jit/jit-rules-x86.h 14 Sep 2006 06:27:08 -0000      1.6
@@ -39,19 +39,21 @@
        {"edi", 7, -1, JIT_REG_WORD | JIT_REG_GLOBAL}, \
        {"ebp", 4, -1, JIT_REG_FRAME | JIT_REG_FIXED}, \
        {"esp", 5, -1, JIT_REG_STACK_PTR | JIT_REG_FIXED | JIT_REG_CALL_USED}, \
-       {"st",  0, -1, JIT_REG_X86_FLOAT | JIT_REG_CALL_USED | \
-                                  JIT_REG_START_STACK | JIT_REG_IN_STACK}, \
+       {"st",  0, -1, JIT_REG_X86_FLOAT | JIT_REG_CALL_USED | 
JIT_REG_IN_STACK}, \
        {"st1", 1, -1, JIT_REG_X86_FLOAT | JIT_REG_CALL_USED | 
JIT_REG_IN_STACK}, \
        {"st2", 2, -1, JIT_REG_X86_FLOAT | JIT_REG_CALL_USED | 
JIT_REG_IN_STACK}, \
        {"st3", 3, -1, JIT_REG_X86_FLOAT | JIT_REG_CALL_USED | 
JIT_REG_IN_STACK}, \
        {"st4", 4, -1, JIT_REG_X86_FLOAT | JIT_REG_CALL_USED | 
JIT_REG_IN_STACK}, \
        {"st5", 5, -1, JIT_REG_X86_FLOAT | JIT_REG_CALL_USED | 
JIT_REG_IN_STACK}, \
        {"st6", 6, -1, JIT_REG_X86_FLOAT | JIT_REG_CALL_USED | 
JIT_REG_IN_STACK}, \
-       {"st7", 7, -1, JIT_REG_X86_FLOAT | JIT_REG_CALL_USED | \
-                                  JIT_REG_END_STACK | JIT_REG_IN_STACK},
+       {"st7", 7, -1, JIT_REG_X86_FLOAT | JIT_REG_CALL_USED | 
JIT_REG_IN_STACK},
 #define        JIT_NUM_REGS            16
 #define        JIT_NUM_GLOBAL_REGS     3
 
+#define JIT_REG_STACK          1
+#define JIT_REG_STACK_START    8
+#define JIT_REG_STACK_END      15
+
 /*
  * Define to 1 if we should always load values into registers
  * before operating on them.  i.e. the CPU does not have reg-mem

Index: jit/jit-rules-x86.ins
===================================================================
RCS file: /sources/dotgnu-pnet/libjit/jit/jit-rules-x86.ins,v
retrieving revision 1.14
retrieving revision 1.15
diff -u -b -r1.14 -r1.15
--- jit/jit-rules-x86.ins       30 Aug 2006 19:23:27 -0000      1.14
+++ jit/jit-rules-x86.ins       14 Sep 2006 06:27:08 -0000      1.15
@@ -1344,25 +1344,13 @@
                inst = jump_to_epilog(gen, inst, block);
        }
 
-JIT_OP_RETURN_INT: unary_branch
+JIT_OP_RETURN_INT: unary_note
        [reg("eax")] -> {
                inst = jump_to_epilog(gen, inst, block);
        }
 
-JIT_OP_RETURN_LONG: unary_branch
-       [imm] -> {
-               x86_mov_reg_imm(inst, X86_EAX,
-                                               ((jit_int 
*)(insn->value1->address))[0]);
-               x86_mov_reg_imm(inst, X86_EDX,
-                                               ((jit_int 
*)(insn->value1->address))[1]);
-               inst = jump_to_epilog(gen, inst, block);
-       }
-       [lreg] -> {
-               if($1 != X86_EAX)
-               {
-                       x86_mov_reg_reg(inst, X86_EAX, $1, 4);
-                       x86_mov_reg_reg(inst, X86_EDX, %1, 4);
-               }
+JIT_OP_RETURN_LONG: unary_note
+       [lreg("eax":"edx")] -> {
                inst = jump_to_epilog(gen, inst, block);
        }
 
@@ -1381,11 +1369,100 @@
                inst = jump_to_epilog(gen, inst, block);
        }
 
-JIT_OP_RETURN_SMALL_STRUCT: unary_branch
-       [reg] -> {
-               inst = load_small_struct
-                       (inst, X86_EAX, X86_EDX, $1, 0,
-                        jit_value_get_nint_constant(insn->value2), 0);
+JIT_OP_RETURN_SMALL_STRUCT: binary_note
+       [reg, imm] -> {
+               switch($2)
+               {
+               case 1:
+                       x86_widen_membase(inst, X86_EAX, $1, 0, 0, 0);
+                       break;
+
+               case 2:
+                       x86_widen_membase(inst, X86_EAX, $1, 0, 0, 1);
+                       break;
+
+               case 3:
+                       if(X86_EAX == $1)
+                       {
+                               x86_widen_membase(inst, X86_EDX, $1, 0, 0, 1);
+                               x86_widen_membase(inst, X86_EAX, $1, 2, 0, 0);
+                       }
+                       else
+                       {
+                               x86_widen_membase(inst, X86_EAX, $1, 2, 0, 0);
+                               x86_widen_membase(inst, X86_EDX, $1, 0, 0, 1);
+                       }
+                       x86_shift_reg_imm(inst, X86_SHL, X86_EAX, 16);
+                       x86_alu_reg_reg(inst, X86_OR, X86_EAX, X86_EDX);
+                       break;
+
+               case 4:
+                       x86_mov_reg_membase(inst, X86_EAX, $1, 0, 4);
+                       break;
+
+               case 5:
+                       if(X86_EAX == $1)
+                       {
+                               x86_widen_membase(inst, X86_EDX, $1, 4, 0, 0);
+                               x86_mov_reg_membase(inst, X86_EAX, $1, 0, 4);
+                       }
+                       else
+                       {
+                               x86_mov_reg_membase(inst, X86_EAX, $1, 0, 4);
+                               x86_widen_membase(inst, X86_EDX, $1, 4, 0, 0);
+                       }
+                       break;
+
+               case 6:
+                       if(X86_EAX == $1)
+                       {
+                               x86_widen_membase(inst, X86_EDX, $1, 4, 0, 1);
+                               x86_mov_reg_membase(inst, X86_EAX, $1, 0, 4);
+                       }
+                       else
+                       {
+                               x86_mov_reg_membase(inst, X86_EAX, $1, 0, 4);
+                               x86_widen_membase(inst, X86_EDX, $1, 4, 0, 1);
+                       }
+                       break;
+
+               case 7:
+                       if(X86_EAX == $1)
+                       {
+                               x86_widen_membase(inst, X86_ECX, $1, 4, 0, 1);
+                               x86_widen_membase(inst, X86_EDX, $1, 6, 0, 0);
+                               x86_mov_reg_membase(inst, X86_EAX, $1, 0, 4);
+                       }
+                       else if(X86_ECX == $1)
+                       {
+                               x86_mov_reg_membase(inst, X86_EAX, $1, 0, 4);
+                               x86_widen_membase(inst, X86_EDX, $1, 6, 0, 0);
+                               x86_widen_membase(inst, X86_ECX, $1, 4, 0, 1);
+                       }
+                       else
+                       {
+                               x86_mov_reg_membase(inst, X86_EAX, $1, 0, 4);
+                               x86_widen_membase(inst, X86_ECX, $1, 4, 0, 1);
+                               x86_widen_membase(inst, X86_EDX, $1, 6, 0, 0);
+                       }
+                       x86_shift_reg_imm(inst, X86_SHL, X86_EDX, 16);
+                       x86_alu_reg_reg(inst, X86_OR, X86_EDX, X86_ECX);
+                       break;
+
+               case 8:
+                       if(X86_EAX == $1)
+                       {
+                               x86_mov_reg_membase(inst, X86_EDX, $1, 4, 4);
+                               x86_mov_reg_membase(inst, X86_EAX, $1, 0, 4);
+                       }
+                       else
+                       {
+                               x86_mov_reg_membase(inst, X86_EAX, $1, 0, 4);
+                               x86_mov_reg_membase(inst, X86_EDX, $1, 4, 4);
+                       }
+                       break;
+               }
+
                inst = jump_to_epilog(gen, inst, block);
        }
 

Index: jit/jit-rules.h
===================================================================
RCS file: /sources/dotgnu-pnet/libjit/jit/jit-rules.h,v
retrieving revision 1.14
retrieving revision 1.15
diff -u -b -r1.14 -r1.15
--- jit/jit-rules.h     29 Aug 2006 11:57:13 -0000      1.14
+++ jit/jit-rules.h     14 Sep 2006 06:27:08 -0000      1.15
@@ -70,10 +70,8 @@
 #define        JIT_REG_STACK_PTR       (1 << 6)        /* Contains CPU stack 
pointer */
 #define        JIT_REG_FIXED           (1 << 7)        /* Fixed use; not for 
allocation */
 #define        JIT_REG_CALL_USED       (1 << 8)        /* Destroyed by a call 
*/
-#define        JIT_REG_START_STACK     (1 << 9)        /* Stack of stack-like 
allocation */
-#define        JIT_REG_END_STACK       (1 << 10)       /* End of stack-like 
allocation */
-#define        JIT_REG_IN_STACK        (1 << 11)       /* Middle of stack-like 
allocation */
-#define        JIT_REG_GLOBAL          (1 << 12)       /* Candidate for global 
allocation */
+#define        JIT_REG_IN_STACK        (1 << 9)        /* Middle of stack-like 
allocation */
+#define        JIT_REG_GLOBAL          (1 << 10)       /* Candidate for global 
allocation */
 #define        JIT_REG_ALL     (JIT_REG_WORD | JIT_REG_LONG | JIT_REG_FLOAT32 
| \
                                         JIT_REG_FLOAT64 | JIT_REG_NFLOAT)
 
@@ -120,7 +118,10 @@
 {
        /* List of values that are currently stored in this register */
        jit_value_t             values[JIT_MAX_REG_VALUES];
-       short                   num_values;
+       int                     num_values;
+
+       /* Current age of this register.  Older registers are reclaimed first */
+       int                     age;
 
        /* Flag that indicates if this register is holding the first
           word of a double-word long value (32-bit platforms only) */
@@ -130,15 +131,9 @@
           word of a double-word long value (32-bit platforms only) */
        char                    is_long_end;
 
-       /* Current age of this register.  Older registers are reclaimed first */
-       int                             age;
-
-       /* Remapped version of this register, when used in a stack */
-       short                   remap;
-
        /* Flag that indicates if the register holds a valid value,
           but there are no actual "jit_value_t" objects associated */
-       short                   used_for_temp;
+       char                    used_for_temp;
 };
 
 /*
@@ -152,8 +147,10 @@
        jit_regused_t           inhibit;        /* Temporarily inhibited 
registers */
        jit_cache_posn          posn;           /* Current cache output 
position */
        jit_regcontents_t       contents[JIT_NUM_REGS]; /* Contents of each 
register */
-       int                                     current_age;/* Current age 
value for registers */
-       int                                     stack_map[JIT_NUM_REGS]; /* 
Reverse stack mappings */
+       int                     current_age;    /* Current age value for 
registers */
+#ifdef JIT_REG_STACK
+       int                     reg_stack_top;  /* Current register stack top */
+#endif
 #ifdef jit_extra_gen_state
        jit_extra_gen_state;                    /* CPU-specific extra 
information */
 #endif




reply via email to

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