]> git.unchartedbackwaters.co.uk Git - francis/libjit.git/commitdiff
remove "old" register allocator;
authorAleksey Demakov <ademakov@gmail.com>
Thu, 14 Sep 2006 06:27:08 +0000 (06:27 +0000)
committerAleksey Demakov <ademakov@gmail.com>
Thu, 14 Sep 2006 06:27:08 +0000 (06:27 +0000)
ChangeLog
jit/jit-reg-alloc.c
jit/jit-reg-alloc.h
jit/jit-rules-x86.c
jit/jit-rules-x86.h
jit/jit-rules-x86.ins
jit/jit-rules.h

index 0a4cfcedba5550458c7b8647cd6cea49362f7c3f..2abc9c29e3226a74b32e51feed40d25fd238d797 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,14 @@
+2006-09-14  Aleksey Demakov  <ademakov@gmail.com>
+
+       * 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  <ademakov@gmail.com>
 
        * jit/jit-reg-alloc.h, jit/jit-reg-alloc.c:
@@ -7,7 +18,7 @@
 
 2006-09-02  Aleksey Demakov  <ademakov@gmail.com>
 
-       * jit/jit-interp.c (_jit_run_function): 
+       * jit/jit-interp.c (_jit_run_function):
        * jit/jit-rules-interp.c (_jit_gen_insn): remove last traces of
        register allocation from the interpreter.
 
index a5608a4bf96ca8c1e90216a3b046164b8fd61cba..d0bf074457a0e2fae7edc160095edd1f54477483 100644 (file)
@@ -32,113 +32,71 @@ mostly don't have to worry about it:
 
 @*/
 
-/*@
- * @deftypefun void _jit_regs_init_for_block (jit_gencode_t gen)
- * Initialize the register allocation state for a new block.
- * @end deftypefun
-@*/
-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
-@*/
-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
-@*/
-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 @@ static void dump_regs(jit_gencode_t gen, const char *name)
                {
                        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,2421 +125,1179 @@ static void dump_regs(jit_gencode_t gen, const char *name)
                {
                        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)
-               {
-                       continue;
-               }
-
-               /* Remember this register if it is the start of a stack */
-               if((_jit_reg_info[reg].flags & JIT_REG_START_STACK) != 0)
+               if(other_reg == OTHER_REG(reg))
                {
-                       first_stack_reg = reg;
+                       return 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
-               {
-                       real_reg = reg;
-               }
+/*
+ * 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;
 
-               /* 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;
+                       return 1;
+               }
+               if(desc1->value->in_register && desc2->value->in_register)
+               {
+                       return desc1->value->reg == desc2->value->reg;
                }
-               spill_all_between(gen, first_reg, reg);
-       }
-}
-
-/*
- * 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)
-       {
-               --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
-@*/
-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)
+       {
+               return flags;
+       }
+       if(value == regs->descs[0].value)
        {
-               ++remap;
-               for(;;)
+               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
-}
-
-/*
- * Make space for a new stack register in a particular stack.
- * Returns the pseudo register number of the newly allocated register.
- */
-static int create_stack_reg(jit_gencode_t gen, int reg, int roll_down)
-{
-       int first_stack_reg;
-       int temp_reg, remap;
-
-#ifdef JIT_REG_DEBUG
-       dump_regs(gen, "enter create_stack_reg");
-#endif
-
-       /* Find the first pseudo register in the stack */
-       while((_jit_reg_info[reg].flags & JIT_REG_START_STACK) == 0)
-       {
-               --reg;
-       }
-       first_stack_reg = reg;
-
-       /* Find a free pseudo register in the stack */
-       for(;;)
+       if(value == regs->descs[1].value)
        {
-               if(gen->contents[reg].num_values == 0 &&
-                  !(gen->contents[reg].used_for_temp))
+               flags |= VALUE_INPUT;
+               if(regs->descs[1].used)
                {
-                       break;
+                       flags |= VALUE_LIVE | VALUE_USED;
                }
-               if((_jit_reg_info[reg].flags & JIT_REG_END_STACK) != 0)
+               else if(regs->descs[1].live)
                {
-                       /* 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;
+                       flags |= VALUE_LIVE;
+               }
+               else
+               {
+                       flags |= VALUE_DEAD;
                }
-               ++reg;
        }
-
-       /* Roll the stack remappings down to make room at the top */
-       if(roll_down)
+       if(value == regs->descs[2].value)
        {
-               temp_reg = first_stack_reg - 1;
-               do
+               flags |= VALUE_INPUT;
+               if(regs->descs[2].used)
                {
-                       ++temp_reg;
-                       remap = gen->contents[temp_reg].remap;
-                       if(remap != -1)
-                       {
-                               /* 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);
-                       }
+                       flags |= VALUE_LIVE | VALUE_USED;
+               }
+               else if(regs->descs[2].live)
+               {
+                       flags |= VALUE_LIVE;
+               }
+               else
+               {
+                       flags |= VALUE_DEAD;
                }
-               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 flags;
 }
 
 /*
- * Free a register, and optionally spill its value.
+ * Check if the register contains any live values.
  */
-static void free_reg_and_spill
-       (jit_gencode_t gen, int reg, int value_used, int spill)
+static int
+is_register_alive(jit_gencode_t gen, _jit_regs_t *regs, int reg)
 {
-       int other_reg, posn;
-       jit_value_t value;
-
-#ifdef JIT_REG_DEBUG
-       dump_regs(gen, "enter free_reg_and_spill");
-#endif
+       int index, usage;
 
-       /* Find the other register in a long pair */
-       if(gen->contents[reg].is_long_start)
-       {
-               other_reg = _jit_reg_info[reg].other_reg;
-               gen->contents[reg].is_long_start = 0;
-               gen->contents[other_reg].is_long_end = 0;
-       }
-       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(other_reg == _jit_reg_info[reg].other_reg)
-                       {
-                               gen->contents[reg].is_long_start = 0;
-                               break;
-                       }
-               }
-       }
-       else
+       if(reg < 0)
        {
-               other_reg = -1;
+               return 0;
        }
 
-       /* Spill the register's contents to the local variable frame */
-       if(spill && gen->contents[reg].num_values > 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))
        {
-               for(posn = gen->contents[reg].num_values - 1; posn >= 0; --posn)
+               if(!regs->ternary
+                  && regs->descs[0].value
+                  && regs->descs[0].value->has_global_register
+                  && regs->descs[0].value->global_reg == reg)
                {
-                       value = gen->contents[reg].values[posn];
-                       if(value->has_global_register)
-                       {
-                               if(!(value->in_global_register))
-                               {
-                                       _jit_gen_spill_reg(gen, 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, reg, other_reg, value);
-                               }
-                               else
-                               {
-                                       _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;
+                       return 0;
                }
+               return 1;
        }
 
-       /* 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)
-       {
-               gen->contents[other_reg].num_values = 0;
-               gen->contents[other_reg].used_for_temp = 0;
-       }
-
-       /* 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(gen->contents[reg].is_long_end)
        {
-               free_stack_reg(gen, reg);
+               reg = get_long_pair_start(reg);
        }
-       if(other_reg != -1 && gen->contents[other_reg].remap != -1)
+       for(index = 0; index < gen->contents[reg].num_values; index++)
        {
-               free_stack_reg(gen, other_reg);
+               usage = value_usage(regs, gen->contents[reg].values[index]);
+               if((usage & VALUE_DEAD) == 0)
+               {
+                       return 1;
+               }
        }
 
-#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);
+       return 0;
 }
 
-/*@
- * @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.
+/*
+ * 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.
  *
- * 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.
+ * 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.
  *
- * 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
-@*/
-int _jit_regs_want_reg(jit_gencode_t gen, int reg, int for_long)
+ * 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 other_reg;
-       if((_jit_reg_info[reg].flags & JIT_REG_IN_STACK) == 0)
+       int flags;
+
+       if(!regs->descs[index].value)
        {
-               /* Spill an ordinary register and its pair register */
-               free_reg_and_spill(gen, reg, 0, 1);
-               if(for_long)
+               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)
                {
-                       other_reg = _jit_reg_info[reg].other_reg;
-                       if(other_reg != -1)
-                       {
-                               free_reg_and_spill(gen, other_reg, 0, 1);
-                       }
+                       flags = CLOBBER_INPUT_VALUE;
                }
                else
                {
-                       other_reg = -1;
+                       flags = CLOBBER_NONE;
                }
-
-               /* Mark the register as touched and return it */
-               jit_reg_set_used(gen->touched, reg);
-               if(other_reg != -1)
+       }
+       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))
                {
-                       jit_reg_set_used(gen->touched, other_reg);
+                       flags |= CLOBBER_REG;
                }
-               return reg;
+               if(is_register_alive(gen, regs, other_reg))
+               {
+                       flags |= CLOBBER_OTHER_REG;
+               }
+               return flags;
        }
-       else
+       else if(regs->on_stack && !regs->no_pop)
        {
-               /* 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);
+               /* this is a binary or unary stack op -- the input value
+                  is either popped or overwritten by the output */
+               flags = CLOBBER_INPUT_VALUE;
        }
-}
-
-/*@
- * @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
-@*/
-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
-@*/
-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))
+       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)
        {
-               other_reg = _jit_reg_info[reg].other_reg;
+               flags = CLOBBER_INPUT_VALUE;
        }
        else
        {
-               other_reg = -1;
+               flags = CLOBBER_NONE;
        }
 
-       /* Mark the register as touched */
-       jit_reg_set_used(gen->touched, reg);
-       if(other_reg != -1)
+       if(flags == CLOBBER_NONE)
        {
-               jit_reg_set_used(gen->touched, other_reg);
+               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;
+               }
        }
 
-       /* 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)
+       if(is_register_alive(gen, regs, reg))
        {
-               gen->contents[reg].is_long_start = 0;
-               gen->contents[reg].is_long_end = 0;
-               gen->contents[reg].used_for_temp = 0;
+               flags |= CLOBBER_REG;
        }
-       else
+       if(is_register_alive(gen, regs, other_reg))
        {
-               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;
+               flags |= CLOBBER_OTHER_REG;
        }
-       (gen->current_age)++;
+       return flags;
+}
 
-       /* Set the stack mappings for this register */
-       if((_jit_reg_info[reg].flags & JIT_REG_IN_STACK) != 0)
+/*
+ * Assign scratch register.
+ */
+static void
+set_scratch_register(jit_gencode_t gen, _jit_regs_t *regs, int index, int reg)
+{
+       if(reg >= 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
+               regs->scratch[index].reg = reg;
 
-       /* Adjust the value to reflect that it is in "reg", and maybe the frame */
-       value->in_register = 1;
-       if(value->has_global_register)
-               value->in_global_register = still_in_frame;
-       else
-               value->in_frame = still_in_frame;
-       value->reg = (short)reg;
+               jit_reg_set_used(gen->touched, reg);
+               jit_reg_set_used(regs->clobber, reg);
+               jit_reg_set_used(regs->assigned, 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
-@*/
-void _jit_regs_set_incoming(jit_gencode_t gen, int reg, jit_value_t value)
+/*
+ * Initialize value descriptor.
+ */
+static void
+init_regdesc(_jit_regs_t *regs, int index)
 {
-       /* Eject any values that are currently in the register */
-       reg = _jit_regs_want_reg(gen, reg, _jit_regs_needs_long_pair(value->type));
+       _jit_regdesc_t *desc;
 
-       /* Record that the value is in "reg", but not in the frame */
-       _jit_regs_set_value(gen, reg, value, 0);
+       desc = &regs->descs[index];
+       desc->value = 0;
+       desc->reg = -1;
+       desc->other_reg = -1;
+       desc->stack_reg = -1;
+       desc->regset = jit_regused_init_used;
+       desc->live = 0;
+       desc->used = 0;
+       desc->clobber = 0;
+       desc->early_clobber = 0;
+       desc->duplicate = 0;
+       desc->thrash = 0;
+       desc->save = 0;
+       desc->load = 0;
+       desc->copy = 0;
+       desc->kill = 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
-@*/
-void _jit_regs_set_outgoing(jit_gencode_t gen, int reg, jit_value_t value)
+/*
+ * Set value information.
+ */
+static void
+set_regdesc_value(_jit_regs_t *regs, int index, jit_value_t value, int flags, int live, int used)
 {
-       int other_reg;
-       int need_pair;
+       _jit_regdesc_t *desc;
 
-#ifdef JIT_BACKEND_X86
-       jit_type_t type;
-       type = jit_type_normalize(value->type);
-       need_pair = 0;
-       if(type)
+       desc = &regs->descs[index];
+       desc->value = value;
+       if(index > 0 || regs->ternary)
        {
-               /* 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)
+               if((flags & _JIT_REGS_EARLY_CLOBBER) != 0)
                {
-                       need_pair = 1;
+                       desc->clobber = 1;
+                       desc->early_clobber = 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))
+               else if((flags & _JIT_REGS_CLOBBER) != 0)
                {
-                       free_reg_and_spill(gen, reg, 1, 1);
+                       desc->clobber = 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
+       desc->live = live;
+       desc->used = used;
+}
+
+/*
+ * Assign register to a value.
+ */
+static void
+set_regdesc_register(jit_gencode_t gen, _jit_regs_t *regs, int index, int reg, int other_reg)
+{
+       int is_output;
+
+       if(reg >= 0)
        {
-               /* Force the value out of whatever register it is already in */
-               _jit_regs_force_out(gen, value, 0);
+               is_output = (index == 0 && !regs->ternary);
 
-               /* Reload the value into the specified register */
-               if(need_pair)
+               regs->descs[index].reg = reg;
+               regs->descs[index].other_reg = other_reg;
+
+               jit_reg_set_used(gen->touched, reg);
+               if(!is_output)
                {
-               #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);
+                       jit_reg_set_used(regs->assigned, reg);
                }
-               else
+               if(other_reg >= 0)
                {
-                       _jit_regs_want_reg(gen, reg, 0);
-                       _jit_gen_load_value(gen, reg, -1, value);
-                       jit_reg_set_used(gen->inhibit, reg);
+                       jit_reg_set_used(gen->touched, other_reg);
+                       if(!is_output)
+                       {
+                               jit_reg_set_used(regs->assigned, other_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
-@*/
-int _jit_regs_is_top(jit_gencode_t gen, jit_value_t value)
+/*
+ * Determine value flags.
+ */
+static int
+set_regdesc_flags(jit_gencode_t gen, _jit_regs_t *regs, int index)
 {
-       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)
+       _jit_regdesc_t *desc;
+       int reg, other_reg;
+       int clobber, clobber_input;
+
+#ifdef JIT_REG_DEBUG
+       printf("set_regdesc_flags(index = %d)\n", index);
+#endif
+
+       desc = &regs->descs[index];
+       if(desc->reg < 0 || desc->duplicate)
        {
                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
-@*/
-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))
+       /* Find the registers the value is already in (if any). */
+       if(desc->value->in_register)
        {
-               return 0;
+               reg = desc->value->reg;
+               if(gen->contents[reg].is_long_start)
+               {
+                       other_reg = OTHER_REG(reg);
+               }
+               else
+               {
+                       other_reg = -1;
+               }
        }
-       reg = value2->reg;
-       if((_jit_reg_info[reg].flags & JIT_REG_IN_STACK) == 0)
+       else
        {
-               reg = value1->reg;
-               return ((_jit_reg_info[reg].flags & JIT_REG_IN_STACK) == 0);
+               reg = -1;
+               other_reg = -1;
        }
-       remap = gen->contents[reg].remap;
-       if(remap == -1 || (_jit_reg_info[remap].flags & JIT_REG_START_STACK) == 0)
+
+       /* See if the value clobbers the register it is assigned to. */
+       clobber = clobbers_register(gen, regs, index, desc->reg, desc->other_reg);
+       if((clobber & CLOBBER_INPUT_VALUE) != 0)
        {
-               return 0;
+               clobber_input = 1;
        }
-       reg = value1->reg;
-       if((_jit_reg_info[reg].flags & JIT_REG_IN_STACK) == 0)
+       else if(jit_reg_is_used(regs->clobber, desc->reg))
        {
-               return 1;
+               clobber_input = 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)
+       else if(desc->other_reg >= 0 && jit_reg_is_used(regs->clobber, desc->other_reg))
        {
-               /* 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);
-               }
+               clobber_input = 1;
        }
        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);
+               clobber_input = 0;
        }
-}
-
-/*
- * 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)
+       if((clobber & CLOBBER_REG) != 0)
        {
-               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;
+               jit_reg_set_used(regs->clobber, desc->reg);
+       }
+       if((clobber & CLOBBER_OTHER_REG) != 0)
+       {
+               jit_reg_set_used(regs->clobber, desc->other_reg);
+       }
 
-               case JIT_TYPE_LONG:
-               case JIT_TYPE_ULONG:
+       /* 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
+          registers the problem of thrashing may be best solved with fxch
+          but as the stack registers are never assigned explicitely there
+          is no such problem for them at all. */
+       if(reg >= 0 && (index > 0 || regs->ternary))
+       {
+               if(index != 0 && regs->ternary && !are_values_equal(desc, &regs->descs[0]))
                {
-                       if(need_pair)
-                               type = JIT_REG_LONG;
-                       else
-                               type = JIT_REG_WORD;
+                       if(reg == regs->descs[0].reg
+                          || reg == regs->descs[0].other_reg
+                          || (other_reg >= 0
+                              && (other_reg == regs->descs[0].reg
+                                  || other_reg == regs->descs[0].other_reg)))
+                       {
+                               desc->thrash = 1;
+                       }
                }
-               break;
-
-               case JIT_TYPE_FLOAT32:
+               if(index != 1 && !are_values_equal(desc, &regs->descs[1]))
                {
-                       type = JIT_REG_FLOAT32;
+                       if(reg == regs->descs[1].reg
+                          || reg == regs->descs[1].other_reg
+                          || (other_reg >= 0
+                              && (other_reg == regs->descs[1].reg
+                                  || other_reg == regs->descs[1].other_reg)))
+                       {
+                               desc->thrash = 1;
+                       }
                }
-               break;
-
-               case JIT_TYPE_FLOAT64:
+               if(index != 2 && !are_values_equal(desc, &regs->descs[2]))
                {
-                       type = JIT_REG_FLOAT64;
+                       if(reg == regs->descs[2].reg
+                          || reg == regs->descs[2].other_reg
+                          || (other_reg >= 0
+                              && (other_reg == regs->descs[2].reg
+                                  || other_reg == regs->descs[2].other_reg)))
+                       {
+                               desc->thrash = 1;
+                       }
                }
-               break;
 
-               case JIT_TYPE_NFLOAT:
+               if(desc->thrash)
                {
-                       type = JIT_REG_NFLOAT;
+                       reg = -1;
+                       other_reg = -1;
+                       desc->save = 1;
                }
-               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(index > 0 || regs->ternary)
        {
-               if((_jit_reg_info[reg].flags & type) != 0 &&
-                  !jit_reg_is_used(gen->permanent, reg) &&
-                  !jit_reg_is_used(gen->inhibit, reg))
+               /* See if the value needs to be loaded or copied or none. */
+               if(desc->value->has_global_register)
                {
-                       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(desc->value->global_reg != desc->reg
+                          && !(reg >= 0 && reg == desc->reg))
                        {
-                               if(gen->contents[reg].num_values == 0 &&
-                                  !(gen->contents[reg].used_for_temp) &&
-                                  !(gen->contents[reg].is_long_end))
-                               {
-                                       return reg;
-                               }
+                               desc->copy = 1;
                        }
-                       else
+               }
+               else
+               {
+                       if(reg < 0)
                        {
-                               *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;
-                               }
+                               desc->load = 1;
                        }
-                       if(suitable_reg == -1 || gen->contents[reg].age < suitable_age)
+                       else if(reg != desc->reg)
                        {
-                               /* This is the oldest suitable register of this type */
-                               suitable_reg = reg;
-                               suitable_age = gen->contents[reg].age;
+                               desc->copy = 1;
                        }
                }
-       }
-
-       /* 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
-@*/
-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)
+               /* See if the input value needs to be saved before the
+                  instruction and if it stays or not in the register
+                  after the instruction. */
+               if(desc->value->is_constant)
+               {
+                       desc->kill = 1;
+               }
+               else if(reg >= 0)
                {
-                       if(gen->contents[reg].num_values == 1 &&
-                          (value->in_frame || value->in_global_register || !used_again))
+                       if(desc->used)
                        {
-                               /* 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)
+                               if(!desc->copy && clobber_input)
                                {
-                                       other_reg = _jit_reg_info[reg].other_reg;
-                                       gen->contents[other_reg].used_for_temp = 1;
-                                       gen->contents[other_reg].age = gen->current_age;
+                                       desc->save = 1;
+                                       desc->kill = 1;
                                }
-                               ++(gen->current_age);
-                               return reg;
                        }
                        else
                        {
-                               /* We need to spill the register and then reload it */
-                               spill_register(gen, reg);
+                               if(desc->live)
+                               {
+                                       desc->save = 1;
+                               }
+                               desc->kill = 1;
                        }
                }
-               else
+               else if(desc->load)
                {
-                       if(gen->contents[reg].num_values == 1 &&
-                          (value->in_frame || value->in_global_register || !used_again))
+                       if(desc->used)
                        {
-                               /* 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;
+                               if(clobber_input)
+                               {
+                                       desc->kill = 1;
+                               }
                        }
-                       gen->contents[reg].age = gen->current_age;
-                       if(need_pair)
+                       else
                        {
-                               other_reg = _jit_reg_info[reg].other_reg;
-                               gen->contents[other_reg].age = gen->current_age;
+                               desc->kill = 1;
                        }
-                       ++(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)
+       /* See if the value clobbers a global register. In this case the global
+          register is pushed onto stack before the instruction and popped back
+          after it. */
+       if(!desc->copy
+          && (!desc->value->has_global_register || desc->value->global_reg != desc->reg)
+          && (jit_reg_is_used(gen->permanent, desc->reg)
+              || (desc->other_reg >= 0 && jit_reg_is_used(gen->permanent, desc->other_reg))))
        {
-               return value->global_reg;
+               desc->kill = 1;
        }
 
-       /* 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
-@*/
-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)
+       if(IS_STACK_REG(desc->reg))
        {
-               reg = value->reg;
-               if(gen->contents[reg].num_values == 1)
+               if(index > 0 || regs->ternary)
                {
-                       value->in_frame = 0;
-                       value->in_global_register = 0;
-                       return reg;
+                       ++(regs->wanted_stack_count);
+                       if(!(desc->load || desc->copy))
+                       {
+                               ++(regs->loaded_stack_count);
+                       }
                }
-               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;
+#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->has_global_register = %d\n", desc->value->has_global_register);
+       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);
+       printf("reg = %d\n", desc->reg);
+       printf("other_reg = %d\n", desc->other_reg);
+       printf("live = %d\n", desc->live);
+       printf("used = %d\n", desc->used);
+       printf("clobber = %d\n", desc->clobber);
+       printf("early_clobber = %d\n", desc->early_clobber);
+       printf("duplicate = %d\n", desc->duplicate);
+       printf("thrash = %d\n", desc->thrash);
+       printf("save = %d\n", desc->save);
+       printf("load = %d\n", desc->load);
+       printf("copy = %d\n", desc->copy);
+       printf("kill = %d\n", desc->kill);
+#endif
+
+       return 1;
 }
 
 /*
- * Determine if "num" stack registers are free in a specific stack.
+ * Compute the register spill cost. The register spill cost is computed as
+ * the sum of spill costs of individual values the register contains. The
+ * spill cost of a value depends on the following factors:
+ *
+ * 1. Values that are not used after the current instruction may be safely
+ *    discareded so their spill cost is taken to be zero.
+ * 2. Values that are spilled to global registers are cheaper than values
+ *    that are spilled into stack frame.
+ * 3. Clean values are cheaper than dirty values.
+ *
+ * NOTE: A value is clean if it was loaded from the stack frame or from a
+ * global register and has not changed since then. Otherwise it is dirty.
+ * There is no need to spill clean values. However their spill cost is
+ * considered to be non-zero so that the register allocator will choose
+ * those registers that do not contain live values over those that contain
+ * live albeit clean values.
+ *
+ * For global registers this function returns the cost of zero. So global
+ * registers have to be handled separately.
  */
-static int stack_regs_free(jit_gencode_t gen, int reg, int num)
+static int
+compute_spill_cost(jit_gencode_t gen, _jit_regs_t *regs, int reg, int other_reg)
 {
-       int first_reg;
+       int cost, index, usage;
+       jit_value_t value;
 
-       /* 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)
+       if(gen->contents[reg].is_long_end)
        {
-               ++reg;
+               reg = get_long_pair_start(reg);
        }
 
-       /* Search for free registers */
-       while(reg >= first_reg)
+       cost = 0;
+       for(index = 0; index < gen->contents[reg].num_values; index++)
        {
-               if(gen->contents[reg].num_values == 0 &&
-                  !(gen->contents[reg].used_for_temp))
+               value = gen->contents[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)
                {
-                       --num;
-                       if(num <= 0)
+                       if(value->in_global_register)
                        {
-                               return 1;
+                               cost += COST_SPILL_CLEAN_GLOBAL;
                        }
-               }
-               --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
-@*/
-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)
+                       else
+                       {
+                               cost += COST_SPILL_DIRTY_GLOBAL;
+                       }
+               }
+               else
                {
-                       if(value->in_frame || value->in_global_register || !used_again)
+                       if(value->in_frame)
                        {
-                               /* 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;
+                               cost += COST_SPILL_CLEAN;
+                       }
+                       else
+                       {
+                               cost += COST_SPILL_DIRTY;
                        }
                }
-               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
-@*/
-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)
+       if(other_reg >= 0)
        {
-               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))
+               for(index = 0; index < gen->contents[other_reg].num_values; index++)
                {
-                       if((value->in_frame || value->in_global_register || !used_again1) &&
-                          (value2->in_frame || value2->in_global_register || !used_again2))
+                       value = gen->contents[other_reg].values[index];
+                       usage = value_usage(regs, value);
+                       if((usage & VALUE_DEAD) != 0)
                        {
-                               /* 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;
+                               /* 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;
+                               }
                        }
                }
-               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;
+       return cost;
 }
 
-/*@
- * @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
-@*/
-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)
+static int
+thrashes_value(jit_gencode_t gen,
+              _jit_regdesc_t *desc, int reg, int other_reg,
+              _jit_regdesc_t *desc2)
 {
-       int reg, reg2, reg3;
+       int reg2, other_reg2;
 
-       /* Determine if the values are already in the top three registers */
-       if(value->in_register && value2->in_register && value3->in_register)
+#if ALLOW_CLOBBER_GLOBAL
+       if(desc2->value->has_global_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))
+               if(desc2->value->global_reg == reg)
+               {
+                       if(desc && desc2->value == desc->value)
                        {
-                               /* 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;
+                               return 0;
                        }
+                       return 1;
+               }
+               if(desc2->value->global_reg == other_reg)
+               {
+                       return 1;
                }
        }
+#endif
 
-       /* 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
-@*/
-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(desc2->value->in_register)
        {
-               if(gen->contents[type_reg].num_values > 0 ||
-                  gen->contents[type_reg].used_for_temp)
+               reg2 = desc2->value->reg;
+               if(reg2 == reg)
+               {
+                       if(are_values_equal(desc2, desc))
+                       {
+                               return 0;
+                       }
+                       return 1;
+               }
+               if(reg2 == other_reg)
                {
-                       ++count;
+                       return 1;
                }
-               if((_jit_reg_info[type_reg].flags & JIT_REG_END_STACK) == 0)
+               if(gen->contents[reg2].is_long_start)
                {
-                       break;
+                       other_reg2 = OTHER_REG(reg2);
+                       if(other_reg2 == reg /*|| other_reg2 == other_reg*/)
+                       {
+                               return 1;
+                       }
                }
-               ++type_reg;
        }
-       return count;
+
+       return 0;
 }
 
-/*@
- * @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
-@*/
-int _jit_regs_new_top(jit_gencode_t gen, jit_value_t value, int type_reg)
+static int
+choose_scratch_register(jit_gencode_t gen, _jit_regs_t *regs, int index)
 {
-       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;
+       int reg, type;
+       int use_cost, spill_cost;
+       int suitable_reg;
+       int suitable_cost;
+       int suitable_age;
 
-       /* Return the allocated register to the caller */
-       return reg;
-}
+       type = JIT_REG_WORD;
 
-/*@
- * @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
-@*/
-void _jit_regs_force_out(jit_gencode_t gen, jit_value_t value, int is_dest)
-{
-       if(value->in_register)
+       suitable_reg = -1;
+       suitable_cost = COST_TOO_MUCH;
+       suitable_age = -1;
+       for(reg = 0; reg < JIT_NUM_REGS; reg++)
        {
-               if((_jit_reg_info[value->reg].flags & JIT_REG_IN_STACK) == 0)
+               if((_jit_reg_info[reg].flags & type) == 0)
                {
-                       free_reg_and_spill(gen, value->reg, 0, !is_dest);
+                       continue;
                }
-               else
+               if(jit_reg_is_used(regs->assigned, reg))
                {
-                       /* Always do a spill for a stack register */
-                       spill_register(gen, value->reg);
+                       continue;
+               }
+               if(!jit_reg_is_used(regs->scratch[index].regset, reg))
+               {
+                       continue;
                }
-       }
-}
-
-/*
- * 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
-@*/
-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 ALLOW_CLOBBER_GLOBAL
+               if(jit_reg_is_used(gen->permanent, reg))
                {
-                       if((_jit_reg_info[reg].flags &
-                                       (JIT_REG_FIXED | JIT_REG_CALL_USED)) == 0)
-                       {
-                               jit_reg_set_used(gen->permanent, reg);
-                       }
+                       use_cost = COST_CLOBBER_GLOBAL;
                }
-               return;
-       }
+               else
+               {
+                       use_cost = 0;
+               }
+#else
+               if(jit_reg_is_used(gen->permanent, reg))
+               {
+                       continue;
+               }
+               use_cost = 0;
+#endif
 
-       /* 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))
+               if(regs->ternary && regs->descs[0].value
+                  && thrashes_value(gen, 0, reg, -1, &regs->descs[0]))
                {
-                       num = (int)(func->builder->value_pool.elems_in_last);
+                       use_cost += COST_THRASH;
                }
-               for(posn = 0; posn < num; ++posn)
+               else if(regs->descs[1].value
+                       && thrashes_value(gen, 0, reg, -1, &regs->descs[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;
-                               }
-                               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;
-               }
-       }
-
-       if(is_register_alive(gen, regs, reg))
-       {
-               flags |= CLOBBER_REG;
-       }
-       if(is_register_alive(gen, regs, other_reg))
-       {
-               flags |= CLOBBER_OTHER_REG;
-       }
-       return flags;
-}
-
-/*
- * Assign scratch register.
- */
-static void
-set_scratch_register(jit_gencode_t gen, _jit_regs_t *regs, int index, int reg)
-{
-       if(reg >= 0)
-       {
-               regs->scratch[index].reg = reg;
-
-               jit_reg_set_used(gen->touched, reg);
-               jit_reg_set_used(regs->clobber, reg);
-               jit_reg_set_used(regs->assigned, reg);
-       }
-}
-
-/*
- * Initialize value descriptor.
- */
-static void
-init_regdesc(_jit_regs_t *regs, int index)
-{
-       _jit_regdesc_t *desc;
-
-       desc = &regs->descs[index];
-       desc->value = 0;
-       desc->reg = -1;
-       desc->other_reg = -1;
-       desc->stack_reg = -1;
-       desc->regset = jit_regused_init_used;
-       desc->live = 0;
-       desc->used = 0;
-       desc->clobber = 0;
-       desc->early_clobber = 0;
-       desc->duplicate = 0;
-       desc->thrash = 0;
-       desc->save = 0;
-       desc->load = 0;
-       desc->copy = 0;
-       desc->kill = 0;
-}
-
-/*
- * Set value information.
- */
-static void
-set_regdesc_value(_jit_regs_t *regs, int index, jit_value_t value, int flags, int live, int used)
-{
-       _jit_regdesc_t *desc;
-
-       desc = &regs->descs[index];
-       desc->value = value;
-       if(index > 0 || regs->ternary)
-       {
-               if((flags & _JIT_REGS_EARLY_CLOBBER) != 0)
-               {
-                       desc->clobber = 1;
-                       desc->early_clobber = 1;
-               }
-               else if((flags & _JIT_REGS_CLOBBER) != 0)
-               {
-                       desc->clobber = 1;
-               }
-       }
-       desc->live = live;
-       desc->used = used;
-}
-
-/*
- * Assign register to a value.
- */
-static void
-set_regdesc_register(jit_gencode_t gen, _jit_regs_t *regs, int index, int reg, int other_reg)
-{
-       int is_output;
-
-       if(reg >= 0)
-       {
-               is_output = (index == 0 && !regs->ternary);
-
-               regs->descs[index].reg = reg;
-               regs->descs[index].other_reg = other_reg;
-
-               jit_reg_set_used(gen->touched, reg);
-               if(!is_output)
-               {
-                       jit_reg_set_used(regs->assigned, reg);
-               }
-               if(other_reg >= 0)
-               {
-                       jit_reg_set_used(gen->touched, other_reg);
-                       if(!is_output)
-                       {
-                               jit_reg_set_used(regs->assigned, other_reg);
-                       }
-               }
-       }
-}
-
-/*
- * Determine value flags.
- */
-static int
-set_regdesc_flags(jit_gencode_t gen, _jit_regs_t *regs, int index)
-{
-       _jit_regdesc_t *desc;
-       int reg, other_reg, stack_start;
-       int clobber, clobber_input;
-
-#ifdef JIT_REG_DEBUG
-       printf("set_regdesc_flags(index = %d)\n", index);
-#endif
-
-       desc = &regs->descs[index];
-       if(desc->reg < 0 || desc->duplicate)
-       {
-               return 1;
-       }
-
-       /* Find the registers the value is already in (if any). */
-       if(desc->value->in_register)
-       {
-               reg = desc->value->reg;
-               if(gen->contents[reg].is_long_start)
-               {
-                       other_reg = OTHER_REG(reg);
-               }
-               else
-               {
-                       other_reg = -1;
-               }
-       }
-       else
-       {
-               reg = -1;
-               other_reg = -1;
-       }
-
-       /* See if the value clobbers the register it is assigned to. */
-       clobber = clobbers_register(gen, regs, index, desc->reg, desc->other_reg);
-       if((clobber & CLOBBER_INPUT_VALUE) != 0)
-       {
-               clobber_input = 1;
-       }
-       else if(jit_reg_is_used(regs->clobber, desc->reg))
-       {
-               clobber_input = 1;
-       }
-       else if(desc->other_reg >= 0 && jit_reg_is_used(regs->clobber, desc->other_reg))
-       {
-               clobber_input = 1;
-       }
-       else
-       {
-               clobber_input = 0;
-       }
-       if((clobber & CLOBBER_REG) != 0)
-       {
-               jit_reg_set_used(regs->clobber, desc->reg);
-       }
-       if((clobber & CLOBBER_OTHER_REG) != 0)
-       {
-               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
-          registers the problem of thrashing may be best solved with fxch
-          but as the stack registers are never assigned explicitely there
-          is no such problem for them at all. */
-       if(reg >= 0 && (index > 0 || regs->ternary))
-       {
-               if(index != 0 && regs->ternary && !are_values_equal(desc, &regs->descs[0]))
-               {
-                       if(reg == regs->descs[0].reg
-                          || reg == regs->descs[0].other_reg
-                          || (other_reg >= 0
-                              && (other_reg == regs->descs[0].reg
-                                  || other_reg == regs->descs[0].other_reg)))
-                       {
-                               desc->thrash = 1;
-                       }
-               }
-               if(index != 1 && !are_values_equal(desc, &regs->descs[1]))
-               {
-                       if(reg == regs->descs[1].reg
-                          || reg == regs->descs[1].other_reg
-                          || (other_reg >= 0
-                              && (other_reg == regs->descs[1].reg
-                                  || other_reg == regs->descs[1].other_reg)))
-                       {
-                               desc->thrash = 1;
-                       }
-               }
-               if(index != 2 && !are_values_equal(desc, &regs->descs[2]))
-               {
-                       if(reg == regs->descs[2].reg
-                          || reg == regs->descs[2].other_reg
-                          || (other_reg >= 0
-                              && (other_reg == regs->descs[2].reg
-                                  || other_reg == regs->descs[2].other_reg)))
-                       {
-                               desc->thrash = 1;
-                       }
-               }
-
-               if(desc->thrash)
-               {
-                       reg = -1;
-                       other_reg = -1;
-                       desc->save = 1;
-               }
-       }
-
-       if(index > 0 || regs->ternary)
-       {
-               /* See if the value needs to be loaded or copied or none. */
-               if(desc->value->has_global_register)
-               {
-                       if(desc->value->global_reg != desc->reg
-                          && !(reg >= 0 && reg == desc->reg))
-                       {
-                               desc->copy = 1;
-                       }
-               }
-               else
-               {
-                       if(reg < 0)
-                       {
-                               desc->load = 1;
-                       }
-                       else if(reg != desc->reg)
-                       {
-                               desc->copy = 1;
-                       }
-               }
-
-               /* See if the input value needs to be saved before the
-                  instruction and if it stays or not in the register
-                  after the instruction. */
-               if(desc->value->is_constant)
-               {
-                       desc->kill = 1;
-               }
-               else if(reg >= 0)
-               {
-                       if(desc->used)
-                       {
-                               if(!desc->copy && clobber_input)
-                               {
-                                       desc->save = 1;
-                                       desc->kill = 1;
-                               }
-                       }
-                       else
-                       {
-                               if(desc->live)
-                               {
-                                       desc->save = 1;
-                               }
-                               desc->kill = 1;
-                       }
+                       use_cost += COST_THRASH;
                }
-               else if(desc->load)
+               else if(regs->descs[2].value
+                       && thrashes_value(gen, 0, reg, -1, &regs->descs[2]))
                {
-                       if(desc->used)
-                       {
-                               if(clobber_input)
-                               {
-                                       desc->kill = 1;
-                               }
-                       }
-                       else
-                       {
-                               desc->kill = 1;
-                       }
+                       use_cost += COST_THRASH;
                }
-       }
-
-       /* See if the value clobbers a global register. In this case the global
-          register is pushed onto stack before the instruction and popped back
-          after it. */
-       if(!desc->copy
-          && (!desc->value->has_global_register || desc->value->global_reg != desc->reg)
-          && (jit_reg_is_used(gen->permanent, desc->reg)
-              || (desc->other_reg >= 0 && jit_reg_is_used(gen->permanent, desc->other_reg))))
-       {
-               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;
-               }
+               spill_cost = compute_spill_cost(gen, regs, reg, -1);
 
-               if(index > 0 || regs->ternary)
+               if((use_cost + spill_cost) < suitable_cost
+                  || (spill_cost > 0 && (use_cost + spill_cost) == suitable_cost
+                      && gen->contents[reg].age < suitable_age))
                {
-                       ++(regs->wanted_stack_count);
-                       if(!(desc->load || desc->copy))
-                       {
-                               ++(regs->loaded_stack_count);
-                       }
+                       suitable_reg = reg;
+                       suitable_cost = use_cost + spill_cost;
+                       suitable_age = gen->contents[reg].age;
                }
        }
 
-#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->has_global_register = %d\n", desc->value->has_global_register);
-       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);
-       printf("reg = %d\n", desc->reg);
-       printf("other_reg = %d\n", desc->other_reg);
-       printf("live = %d\n", desc->live);
-       printf("used = %d\n", desc->used);
-       printf("clobber = %d\n", desc->clobber);
-       printf("early_clobber = %d\n", desc->early_clobber);
-       printf("duplicate = %d\n", desc->duplicate);
-       printf("thrash = %d\n", desc->thrash);
-       printf("save = %d\n", desc->save);
-       printf("load = %d\n", desc->load);
-       printf("copy = %d\n", desc->copy);
-       printf("kill = %d\n", desc->kill);
-#endif
+       if(suitable_reg >= 0)
+       {
+               set_scratch_register(gen, regs, index, suitable_reg);
+               return 1;
+       }
 
-       return 1;
+       return 0;
 }
 
-/*
- * Compute the register spill cost. The register spill cost is computed as
- * the sum of spill costs of individual values the register contains. The
- * spill cost of a value depends on the following factors:
- *
- * 1. Values that are not used after the current instruction may be safely
- *    discareded so their spill cost is taken to be zero.
- * 2. Values that are spilled to global registers are cheaper than values
- *    that are spilled into stack frame.
- * 3. Clean values are cheaper than dirty values.
- *
- * NOTE: A value is clean if it was loaded from the stack frame or from a
- * global register and has not changed since then. Otherwise it is dirty.
- * There is no need to spill clean values. However their spill cost is
- * considered to be non-zero so that the register allocator will choose
- * those registers that do not contain live values over those that contain
- * live albeit clean values.
- *
- * For global registers this function returns the cost of zero. So global
- * registers have to be handled separately.
- */
 static int
-compute_spill_cost(jit_gencode_t gen, _jit_regs_t *regs, int reg, int other_reg)
+choose_output_register(jit_gencode_t gen, _jit_regs_t *regs)
 {
-       int cost, index, usage;
-       jit_value_t value;
+       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;
 
-       if(gen->contents[reg].is_long_end)
+       need_pair = _jit_regs_needs_long_pair(regs->descs[0].value->type);
+       type = get_register_type(regs->descs[0].value, need_pair);
+       if(!type)
        {
-               reg = get_long_pair_start(reg);
+               return 0;
        }
 
-       cost = 0;
-       for(index = 0; index < gen->contents[reg].num_values; index++)
+       suitable_reg = -1;
+       suitable_other_reg = -1;
+       suitable_cost = COST_TOO_MUCH;
+       suitable_age = -1;
+       for(reg = 0; reg < JIT_NUM_REGS; reg++)
        {
-               value = gen->contents[reg].values[index];
-               usage = value_usage(regs, value);
-               if((usage & VALUE_DEAD) != 0)
+               if((_jit_reg_info[reg].flags & type) == 0)
                {
-                       /* the value is not spilled */
                        continue;
                }
-               if((usage & VALUE_LIVE) != 0 && (usage & VALUE_USED) == 0)
+               if(jit_reg_is_used(gen->inhibit, reg))
                {
-                       /* 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(!jit_reg_is_used(regs->descs[0].regset, reg))
                {
-                       if(value->in_global_register)
-                       {
-                               cost += COST_SPILL_CLEAN_GLOBAL;
-                       }
-                       else
+                       continue;
+               }
+
+               if(need_pair)
+               {
+                       other_reg = OTHER_REG(reg);
+                       if(jit_reg_is_used(gen->inhibit, other_reg))
                        {
-                               cost += COST_SPILL_DIRTY_GLOBAL;
+                               continue;
                        }
                }
                else
                {
-                       if(value->in_frame)
+                       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)
                        {
-                               cost += COST_SPILL_CLEAN;
+                               use_cost = 0;
                        }
                        else
                        {
-                               cost += COST_SPILL_DIRTY;
+                               continue;
                        }
                }
-       }
-       if(other_reg >= 0)
-       {
-               for(index = 0; index < gen->contents[other_reg].num_values; index++)
+               else
                {
-                       value = gen->contents[other_reg].values[index];
-                       usage = value_usage(regs, value);
-                       if((usage & VALUE_DEAD) != 0)
+                       if(other_reg >= 0 && jit_reg_is_used(gen->permanent, other_reg))
                        {
-                               /* the value is not spilled */
                                continue;
                        }
-                       if((usage & VALUE_LIVE) != 0 && (usage & VALUE_USED) == 0)
+                       if(regs->descs[0].value->has_global_register)
                        {
-                               /* the value has to be spilled anyway */
-                               /* NOTE: This is true for local register allocation,
-                                  review for future global allocator. */
-                               continue;
+                               use_cost = COST_GLOBAL_BIAS;
                        }
-                       if(value->has_global_register)
+                       else
                        {
-                               if(value->in_global_register)
-                               {
-                                       cost += COST_SPILL_CLEAN_GLOBAL;
-                               }
-                               else
-                               {
-                                       cost += COST_SPILL_DIRTY_GLOBAL;
-                               }
+                               use_cost = 0;
+                       }
+               }
+
+               if(regs->free_dest)
+               {
+                       /* noop */
+               }
+               else if(regs->descs[1].value
+                       && regs->descs[1].value->in_register
+                       && regs->descs[1].value->reg == reg)
+               {
+                       /* noop */
+               }
+               else if(regs->descs[2].value
+                       && regs->descs[2].value->in_register
+                       && regs->descs[2].value->reg == reg)
+               {
+                       if(regs->commutative || regs->x87_arith)
+                       {
+                               /* noop */
                        }
                        else
                        {
-                               if(value->in_frame)
-                               {
-                                       cost += COST_SPILL_CLEAN;
-                               }
-                               else
-                               {
-                                       cost += COST_SPILL_DIRTY;
-                               }
+                               use_cost += COST_THRASH;
                        }
                }
+               else
+               {
+                       use_cost += COST_COPY;
+               }
+
+               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))
+               {
+                       suitable_reg = reg;
+                       suitable_other_reg = other_reg;
+                       suitable_cost = use_cost + spill_cost;
+                       suitable_age = gen->contents[reg].age;
+               }
        }
-       return cost;
+
+       if(suitable_reg >= 0)
+       {
+               set_regdesc_register(gen, regs, 0, suitable_reg, suitable_other_reg);
+               return 1;
+       }
+
+       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(regs->on_stack && regs->x87_arith)
                {
-                       if(desc && desc2->value == desc->value)
-                       {
-                               return 0;
-                       }
-                       return 1;
+                       regs->no_pop = 1;
+                       regs->reverse_dest = 1;
+                       regs->dest_input_index = 2;
                }
-               if(desc2->value->global_reg == other_reg)
+               else
                {
-                       return 1;
+                       if(regs->commutative)
+                       {
+                               temp_desc = regs->descs[1];
+                               regs->descs[1] = regs->descs[2];
+                               regs->descs[2] = temp_desc;
+                       }
+                       regs->dest_input_index = 1;
                }
        }
-#endif
+       else if(regs->descs[1].value)
+       {
+               regs->dest_input_index = 1;
+       }
+       else
+       {
+               regs->dest_input_index = 0;
+       }
 
-       if(desc2->value->in_register)
+       /* 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)
        {
-               reg2 = desc2->value->reg;
-               if(reg2 == reg)
+               /* 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(are_values_equal(desc2, desc))
-                       {
-                               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)
+               if(regs->descs[2].value->in_register)
                {
-                       other_reg2 = OTHER_REG(reg2);
-                       if(other_reg2 == reg /*|| other_reg2 == other_reg*/)
-                       {
-                               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 @@ choose_scratch_register(jit_gencode_t gen, _jit_regs_t *regs, int index)
                {
                        continue;
                }
-               if(!jit_reg_is_used(regs->scratch[index].regset, reg))
+               if(!jit_reg_is_used(desc->regset, reg))
                {
                        continue;
                }
 
-#if ALLOW_CLOBBER_GLOBAL
-               if(jit_reg_is_used(gen->permanent, reg))
+               if(need_pair)
                {
-                       use_cost = COST_CLOBBER_GLOBAL;
+                       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
-               if(jit_reg_is_used(gen->permanent, reg))
+               else
                {
-                       continue;
+                       use_cost = COST_COPY;
+               }
+               if(desc2->value->has_global_register && desc2->value->global_reg != reg)
+               {
+                       use_cost += COST_GLOBAL_BIAS;
                }
-               use_cost = 0;
-#endif
 
-               if(regs->ternary && regs->descs[0].value
-                  && thrashes_value(gen, 0, reg, -1, &regs->descs[0]))
+               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(regs->descs[1].value
-                       && thrashes_value(gen, 0, reg, -1, &regs->descs[1]))
+               else if(index != 1 && regs->descs[1].value
+                       && thrashes_value(gen, desc, reg, other_reg, &regs->descs[1]))
                {
                        use_cost += COST_THRASH;
                }
-               else if(regs->descs[2].value
-                       && thrashes_value(gen, 0, reg, -1, &regs->descs[2]))
+               else if(index != 2 && regs->descs[2].value
+                       && thrashes_value(gen, desc, reg, other_reg, &regs->descs[2]))
                {
                        use_cost += COST_THRASH;
                }
 
-               spill_cost = compute_spill_cost(gen, regs, reg, -1);
+               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;
+                       }
+#endif
+                       if(jit_reg_is_used(regs->clobber, reg)
+                          || (other_reg >= 0 && jit_reg_is_used(regs->clobber, other_reg)))
+                       {
+                               spill_cost = 0;
+                       }
+                       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;
+                       }
+#endif
+               }
+               else
+               {
+                       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;
                }
@@ -2645,1189 +1413,1345 @@ choose_scratch_register(jit_gencode_t gen, _jit_regs_t *regs, int index)
 
        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;
+
+       return 0;
+}
+
+/*
+ * Assign diplicate input value to the same register if possible.
+ * The first value has to be already assigned. The second value
+ * is assigned to the same register if it is equal to the first
+ * and neither of them is clobbered.
+ */
+static void
+check_duplicate_value(_jit_regs_t *regs, _jit_regdesc_t *desc1, _jit_regdesc_t *desc2)
+{
+       if((!regs->on_stack || regs->x87_arith)
+          && are_values_equal(desc1, desc2)
+          && desc1->reg >= 0 && desc2->reg < 0
+          && !desc1->early_clobber && !desc2->early_clobber)
+       {
+               desc2->reg = desc1->reg;
+               desc2->other_reg = desc1->other_reg;
+               desc2->duplicate = 1;
+       }
 }
 
-static int
-choose_output_register(jit_gencode_t gen, _jit_regs_t *regs)
+#ifdef JIT_REG_STACK
+static void
+adjust_assignment(jit_gencode_t gen, _jit_regs_t *regs, int index)
 {
-       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;
+       _jit_regdesc_t *desc;
 
-       need_pair = _jit_regs_needs_long_pair(regs->descs[0].value->type);
-       type = get_register_type(regs->descs[0].value, need_pair);
-       if(!type)
+       desc = &regs->descs[index];
+       if(!desc->value || !IS_STACK_REG(desc->reg))
        {
-               return 0;
+               return;
        }
 
-       suitable_reg = -1;
-       suitable_other_reg = -1;
-       suitable_cost = COST_TOO_MUCH;
-       suitable_age = -1;
-       for(reg = 0; reg < JIT_NUM_REGS; reg++)
+       if(regs->wanted_stack_count == 1)
        {
-               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))
+               /* either a unary op or a binary op with duplicate value */
+               desc->reg = gen->reg_stack_top - regs->loaded_stack_count;
+       }
+       else if(regs->wanted_stack_count == 2)
+       {
+               /* a binary op */
+
+               /* find the input value the output goes to */
+               if(index == 0)
                {
-                       continue;
+                       index = regs->dest_input_index;
                }
 
-               if(need_pair)
+               if(regs->x87_arith && desc->value->in_register && !desc->copy)
                {
-                       other_reg = OTHER_REG(reg);
-                       if(jit_reg_is_used(gen->inhibit, other_reg))
-                       {
-                               continue;
-                       }
+                       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))
-               {
-                       if(regs->descs[0].value->has_global_register
-                          && regs->descs[0].value->global_reg == reg)
-                       {
-                               use_cost = 0;
-                       }
-                       else
-                       {
-                               continue;
-                       }
-               }
-               else
+#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))
+       {
+               desc1 = &regs->descs[1];
+               desc2 = &regs->descs[2];
+
+               if(desc1->value->in_register && !desc1->copy
+                  && desc2->value->in_register && !desc2->copy)
                {
-                       if(other_reg >= 0 && jit_reg_is_used(gen->permanent, other_reg))
+                       /* Is any of the input values on the stack top? */
+                       if(desc1->value->reg == (gen->reg_stack_top - 1))
                        {
-                               continue;
+                               top_index = 1;
                        }
-                       if(regs->descs[0].value->has_global_register)
+                       else if(desc2->value->reg == (gen->reg_stack_top - 1))
                        {
-                               use_cost = COST_GLOBAL_BIAS;
+                               top_index = 2;
                        }
                        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)
+               else if(desc1->value->in_register && !desc1->copy)
                {
-                       /* noop */
+                       top_index = 2;
                }
-               else if(regs->descs[1].value
-                       && regs->descs[1].value->in_register
-                       && regs->descs[1].value->reg == reg)
+               else if(desc2->value->in_register && !desc2->copy)
                {
-                       /* noop */
+                       top_index = 1;
                }
-               else if(regs->descs[2].value
-                       && regs->descs[2].value->in_register
-                       && regs->descs[2].value->reg == reg)
+               else
                {
-                       if(regs->commutative || regs->x87_arith)
+                       /* TODO: see if the next instruction wants output or remaining
+                          input to be on the stack top. */
+                       top_index = 2;
+               }
+
+               if(top_index == 1)
+               {
+                       if(regs->reversible)
                        {
-                               /* noop */
+                               regs->reverse_args = 1;
                        }
-                       else
+                       else /*if(regs->commutative)*/
                        {
-                               use_cost += COST_THRASH;
+                               temp_desc = *desc1;
+                               *desc1 = *desc2;
+                               *desc2 = temp_desc;
                        }
+                       regs->reverse_dest ^= 1;
                }
-               else
-               {
-                       use_cost += COST_COPY;
-               }
+       }
+}
+#endif
 
-               spill_cost = compute_spill_cost(gen, regs, reg, other_reg);
+/*
+ * 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
 
-               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_other_reg = other_reg;
-                       suitable_cost = use_cost + spill_cost;
-                       suitable_age = gen->contents[reg].age;
-               }
+       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)
+       {
+               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;
        }
+}
 
-       if(suitable_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)
+{
+#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(value->has_global_register && value->global_reg == reg)
        {
-               set_regdesc_register(gen, regs, 0, suitable_reg, suitable_other_reg);
-               return 1;
+               value->in_register = 0;
+               value->in_global_register = 1;
+               return;
        }
 
-       return 0;
+       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);
+
+       /* 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;
 }
 
 /*
- * 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)
+       value->in_register = 0;
+       value->reg = -1;
+
+       for(index = gen->contents[reg].num_values - 1; index >= 0; --index)
        {
-               if(regs->on_stack && regs->x87_arith)
-               {
-                       regs->no_pop = 1;
-                       regs->reverse_dest = 1;
-                       regs->dest_input_index = 2;
-               }
-               else
+               if(gen->contents[reg].values[index] == value)
                {
-                       if(regs->commutative)
+                       --(gen->contents[reg].num_values);
+                       for(; index < gen->contents[reg].num_values; index++)
                        {
-                               temp_desc = regs->descs[1];
-                               regs->descs[1] = regs->descs[2];
-                               regs->descs[2] = temp_desc;
+                               gen->contents[reg].values[index] = gen->contents[reg].values[index + 1];
                        }
-                       regs->dest_input_index = 1;
+                       break;
                }
        }
-       else if(regs->descs[1].value)
-       {
-               regs->dest_input_index = 1;
-       }
-       else
-       {
-               regs->dest_input_index = 0;
-       }
 
-       /* 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(gen->contents[reg].num_values == 0 && other_reg >= 0)
        {
-               /* Determine if we might want to keep either of input values
-                  in registers after the instruction completion. */
-               if(regs->descs[1].value->in_register)
-               {
-                       keep1 = is_register_alive(gen, regs, regs->descs[1].value->reg);
-               }
-               else
-               {
-                       keep1 = (regs->descs[1].used
-                                && (regs->descs[1].value != regs->descs[0].value)
-                                && !regs->descs[1].clobber);
-               }
-               if(regs->descs[2].value->in_register)
-               {
-                       keep2 = is_register_alive(gen, regs, regs->descs[2].value->reg);
-               }
-               else
-               {
-                       keep2 = (regs->descs[2].used
-                                && (regs->descs[2].value != regs->descs[0].value)
-                                && !regs->descs[2].clobber);
-               }
-
-               regs->no_pop = (keep1 || keep2);
+               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)
-               {
-                       continue;
-               }
-               if(jit_reg_is_used(regs->assigned, reg))
-               {
-                       continue;
-               }
-               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;
-               }
+               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(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]))
+               if(value1)
                {
-                       use_cost += COST_THRASH;
+                       value1->reg = reg;
                }
+               gen->contents[reg].values[index] = value1;
 
-               clobber = clobbers_register(gen, regs, index, reg, other_reg);
-               if((clobber & CLOBBER_INPUT_VALUE) != 0)
+               if(pop)
                {
-                       if(desc->used)
+                       if(value2)
                        {
-                               use_cost += COST_SPILL_CLEAN;
+                               value2->reg = -1;
                        }
+                       gen->contents[top].values[index] = 0;
                }
-               if((clobber & (CLOBBER_REG | CLOBBER_OTHER_REG)) != 0)
+               else
                {
-                       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;
-                       }
-#endif
-                       if(jit_reg_is_used(regs->clobber, reg)
-                          || (other_reg >= 0 && jit_reg_is_used(regs->clobber, other_reg)))
-                       {
-                               spill_cost = 0;
-                       }
-                       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))
+                       if(value2)
                        {
-                               spill_cost += COST_CLOBBER_GLOBAL;
+                               value2->reg = top;
                        }
-#endif
-               }
-               else
-               {
-                       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;
+                       gen->contents[top].values[index] = value2;
                }
        }
 
-       if(suitable_reg >= 0)
+       if(pop)
        {
-               set_regdesc_register(gen, regs, index, suitable_reg, suitable_other_reg);
-               return 1;
+               num_values = 0;
+               used_for_temp = 0;
+               age = 0;
        }
-
-       return 0;
-}
-
-/*
- * Assign diplicate input value to the same register if possible.
- * The first value has to be already assigned. The second value
- * is assigned to the same register if it is equal to the first
- * and neither of them is clobbered.
- */
-static void
-check_duplicate_value(_jit_regs_t *regs, _jit_regdesc_t *desc1, _jit_regdesc_t *desc2)
-{
-       if((!regs->on_stack || regs->x87_arith)
-          && are_values_equal(desc1, desc2)
-          && desc1->reg >= 0 && desc2->reg < 0
-          && !desc1->early_clobber && !desc2->early_clobber)
-       {
-               desc2->reg = desc1->reg;
-               desc2->other_reg = desc1->other_reg;
-               desc2->duplicate = 1;
+       else
+       {
+               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
 
+/*
+ * Drop value from the register and optionally bind a temporary value in place of it.
+ */
 static void
-adjust_assignment(jit_gencode_t gen, _jit_regs_t *regs, int index)
+free_value(jit_gencode_t gen, jit_value_t value, int reg, int other_reg, int temp)
 {
-       _jit_regdesc_t *desc;
+#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
 
-       desc = &regs->descs[index];
-       if(!desc->value || !IS_STACK_REG(desc->reg))
+       /* Never free global registers. */
+       if(value->has_global_register && value->global_reg == reg)
        {
                return;
        }
 
-       if(regs->wanted_stack_count == 1)
+       if(gen->contents[reg].num_values == 1)
        {
-               /* either a unary op or binary x87 op with duplicate value */
-               desc->reg = regs->current_stack_top - regs->loaded_stack_count + 1;
+               if(temp)
+               {
+                       unbind_value(gen, value, reg, other_reg);
+                       bind_temporary(gen, reg, other_reg);
+                       return;
+               }
+#ifdef JIT_REG_STACK
+               if(IS_STACK_REG(reg))
+               {
+                       /* Free stack register. */
+                       exch_stack_top(gen, reg, 1);
+               }
+#endif
        }
-       else if(regs->wanted_stack_count == 2)
-       {
-               /* a binary op */
 
-               /* find the input value the output goes to */
-               if(index == 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)
+       {
+               /* Never free global registers. */
+               if(value->global_reg == reg)
                {
-                       index = 1 + (regs->reverse_dest ^ regs->reverse_args);
+                       return;
                }
 
-               if(regs->x87_arith && desc->value->in_register && !desc->copy)
+               if(!value->in_global_register)
                {
-                       desc->reg = desc->value->reg;
+                       _jit_gen_spill_reg(gen, reg, other_reg, value);
+                       value->in_global_register = 1;
                }
-               else
+               if(free)
                {
-                       desc->reg = regs->current_stack_top - regs->loaded_stack_count + index;
+                       unbind_value(gen, value, reg, other_reg);
                }
+               return;
        }
-       else if(regs->wanted_stack_count == 3)
+
+       /* Take care of constants and values that are already in frame. */
+       if(value->is_constant || value->in_frame)
        {
-               /* a ternary op */
-               desc->reg = regs->current_stack_top - regs->loaded_stack_count + index + 1;
+               if(free)
+               {
+                       free_value(gen, value, reg, other_reg, (free == 2));
+               }
+               return;
        }
-}
-
-static void
-select_stack_order(jit_gencode_t gen, _jit_regs_t *regs)
-{
-       _jit_regdesc_t *desc1;
-       _jit_regdesc_t *desc2;
-       _jit_regdesc_t temp_desc;
-       int top_index;
 
-       /* Choose instruction that results into fewer exchanges. */
-       if(regs->on_stack && regs->no_pop && (regs->commutative || regs->reversible))
+       /* Now really save the value into the frame. */
+#ifdef JIT_REG_STACK
+       if(IS_STACK_REG(reg))
        {
-               desc1 = &regs->descs[1];
-               desc2 = &regs->descs[2];
+               int top;
 
-               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)
-                       {
-                               top_index = 1;
-                       }
-                       else if(desc1->value->reg == regs->current_stack_top)
-                       {
-                               top_index = 2;
-                       }
-                       else
-                       {
-                               /* 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)
+               /* 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)
                {
-                       top_index = 2;
+                       exch_stack_top(gen, reg, 0);
                }
-               else if(desc2->value->in_register && !desc2->copy)
+
+               if(free && gen->contents[top].num_values == 1)
                {
-                       top_index = 1;
+                       _jit_gen_spill_top(gen, top, value, 1);
+                       --(gen->reg_stack_top);
                }
                else
                {
-                       /* TODO: see if the next instruction wants output or remaining
-                          input to be on the stack top. */
-                       top_index = 2;
+                       _jit_gen_spill_top(gen, top, value, 0);
                }
+       }
+       else
+#endif
+       {
+               _jit_gen_spill_reg(gen, reg, other_reg, value);
+       }
 
-               if(top_index == 1)
-               {
-                       if(regs->reversible)
-                       {
-                               regs->reverse_args = 1;
-                       }
-                       else /*if(regs->commutative)*/
-                       {
-                               temp_desc = *desc1;
-                               *desc1 = *desc2;
-                               *desc2 = temp_desc;
-                       }
-                       regs->reverse_dest ^= 1;
-               }
+       if(free)
+       {
+               unbind_value(gen, value, reg, other_reg);
        }
+       value->in_frame = 1;
 }
 
+/*
+ * Spill a specific register.
+ */
 static void
-remap_stack_up(jit_gencode_t gen, int stack_start, int reg)
+spill_register(jit_gencode_t gen, int reg)
 {
-       int index;
+       int other_reg, index;
+       jit_value_t value;
 
 #ifdef JIT_REG_DEBUG
-       printf("remap_stack_up(stack_start = %d, reg = %d)\n", stack_start, reg);
+       printf("spill_register(reg = %d)\n", reg);
 #endif
 
-       for(index = stack_start; index < reg; index++)
+       /* Find the other register in a long pair */
+       if(gen->contents[reg].is_long_start)
        {
-               if(gen->contents[index].remap >= 0)
-               {
-                       ++(gen->contents[index].remap);
-                       gen->stack_map[gen->contents[index].remap] = index;
-               }
+               other_reg = OTHER_REG(reg);
+       }
+       else if(gen->contents[reg].is_long_end)
+       {
+               other_reg = reg;
+               reg = get_long_pair_start(reg);
+       }
+       else
+       {
+               other_reg = -1;
+       }
+
+       for(index = gen->contents[reg].num_values - 1; index >= 0; --index)
+       {
+               value = gen->contents[reg].values[index];
+               save_value(gen, value, reg, other_reg, 1);
        }
-       gen->contents[reg].remap = stack_start;
-       gen->stack_map[stack_start] = reg;
 }
 
+/*
+ * Spill a register clobbered by the instruction.
+ */
 static void
-remap_stack_down(jit_gencode_t gen, int stack_start, int reg)
+spill_clobbered_register(jit_gencode_t gen, _jit_regs_t *regs, int reg)
 {
-       int index;
+       int other_reg, index, usage;
+       jit_value_t value;
 
 #ifdef JIT_REG_DEBUG
-       printf("remap_stack_down(stack_start = %d, reg = %d)\n", stack_start, reg);
+       printf("spill_clobbered_register(reg = %d)\n", reg);
 #endif
 
-       gen->stack_map[gen->contents[stack_start].remap] = -1;
-       for(index = stack_start; index < reg; index++)
+       /* 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
+       {
+               other_reg = -1;
+       }
+
+       /* 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))
+       {
+               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);
+                       }
+               }
+       }
+       for(index = gen->contents[reg].num_values - 1; index >= 0; --index)
        {
-               if(gen->contents[index].remap >= 0)
+               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
+                       {
+                               save_value(gen, value, reg, other_reg, 0);
+                       }
+               }
+               else
                {
-                       --(gen->contents[index].remap);
-                       gen->stack_map[gen->contents[index].remap] = index;
+                       if((usage & VALUE_INPUT) == 0)
+                       {
+                               free_value(gen, value, reg, other_reg, 0);
+                       }
                }
        }
-       gen->contents[reg].remap = -1;
 }
 
-/*
- * Associate a temporary with register.
- */
 static void
-bind_temporary(jit_gencode_t gen, int reg, int other_reg)
+update_age(jit_gencode_t gen, _jit_regdesc_t *desc)
 {
-#ifdef JIT_REG_DEBUG
-       printf("bind_temporary(reg = %d, other_reg = %d)\n", reg, other_reg);
-#endif
+       int reg, other_reg;
 
-       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;
+       reg = desc->value->reg;
+       if(gen->contents[reg].is_long_start)
+       {
+               other_reg = OTHER_REG(reg);
+       }
+       else
+       {
+               other_reg = -1;
+       }
+
+       gen->contents[reg].age = gen->current_age;
        if(other_reg >= 0)
        {
-               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;
+               gen->contents[other_reg].age = gen->current_age;
        }
+       ++(gen->current_age);
 }
 
-/*
- * 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)
+save_input_value(jit_gencode_t gen, _jit_regs_t *regs, int index)
 {
-#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);
+       _jit_regdesc_t *desc;
+       int reg, other_reg;
+
+#ifdef JIT_REG_DEBUG
+       printf("save_input_value(%d)\n", index);
 #endif
 
-       if(value->has_global_register && value->global_reg == reg)
+       desc = &regs->descs[index];
+       if(!(desc->value && desc->value->in_register && desc->save))
        {
-               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)
+       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)
+       if(desc->thrash)
        {
-               value->in_global_register = still_in_frame;
+               save_value(gen, desc->value, reg, other_reg, 1);
        }
        else
        {
-               value->in_frame = still_in_frame;
+               save_value(gen, desc->value, reg, other_reg, 0);
        }
-       value->reg = reg;
 }
 
-/*
- * Disassociate value with register.
- */
 static void
-unbind_value(jit_gencode_t gen, jit_value_t value, int reg, int other_reg)
+free_output_value(jit_gencode_t gen, _jit_regs_t *regs)
 {
-       int index;
+       _jit_regdesc_t *desc;
+       int reg, other_reg;
 
 #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("free_output_value()\n");
 #endif
 
-       if(!value->in_register || value->reg != reg)
+       desc = &regs->descs[0];
+       if(!(desc->value && desc->value->in_register))
        {
                return;
        }
-
-       value->in_register = 0;
-       value->reg = -1;
-
-       for(index = gen->contents[reg].num_values - 1; index >= 0; --index)
+       if(desc->value == regs->descs[1].value || desc->value == regs->descs[2].value)
        {
-               if(gen->contents[reg].values[index] == value)
-               {
-                       --(gen->contents[reg].num_values);
-                       for(; index < gen->contents[reg].num_values; index++)
-                       {
-                               gen->contents[reg].values[index] = gen->contents[reg].values[index + 1];
-                       }
-                       break;
-               }
+               return;
        }
 
-       if(gen->contents[reg].num_values == 0 && other_reg >= 0)
+       reg = desc->value->reg;
+       if(gen->contents[reg].is_long_start)
        {
-               gen->contents[reg].is_long_start = 0;
-               gen->contents[other_reg].is_long_end = 0;
+               other_reg = OTHER_REG(reg);
+       }
+       else
+       {
+               other_reg = -1;
        }
+
+       free_value(gen, desc->value, reg, other_reg, 0);
 }
 
-/*
- * Swap the contents of a register and the top of the register stack. If
- * the register is not a stack register then the function has no effect.
- */
 static void
-exch_stack_top(jit_gencode_t gen, int reg, int pop)
+load_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;
 
 #ifdef JIT_REG_DEBUG
-       printf("exch_stack_top(reg = %d, pop = %d)\n", reg, pop);
+       printf("load_input_value(%d)\n", index);
 #endif
 
-       if(!IS_STACK_REG(reg))
+       desc = &regs->descs[index];
+       if(!desc->value || desc->duplicate)
        {
                return;
        }
 
-       /* Find the top of the stack. */
-       stack_start = get_stack_start(reg);
-       top = get_stack_top(gen, stack_start);
-
-       if(pop)
-       {
-               /* Generate move/pop-top instruction. */
-               _jit_gen_move_top(gen, reg);
-               remap_stack_down(gen, stack_start, top);
-       }
-       else
+       if(desc->value->has_global_register)
        {
-               /* Generate exchange instruction. */
-               _jit_gen_exch_top(gen, reg);
+               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);
        }
-
-       /* Update information about the contents of the registers.  */
-       for(index = 0;
-           index < gen->contents[reg].num_values || index < gen->contents[top].num_values;
-           index++)
+       else if(desc->value->in_register)
        {
-               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)
+               if(desc->value->reg == desc->reg)
                {
-                       value1->reg = reg;
+                       update_age(gen, desc);
+                       if(IS_STACK_REG(desc->reg))
+                       {
+                               desc->stack_reg = desc->reg;
+                       }
+                       return;
                }
-               gen->contents[reg].values[index] = value1;
 
-               if(pop)
+#ifdef JIT_REG_STACK
+               if(IS_STACK_REG(desc->reg))
                {
-                       if(value2)
-                       {
-                               value2->reg = -1;
-                       }
-                       gen->contents[top].values[index] = 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
                {
-                       if(value2)
-                       {
-                               value2->reg = top;
-                       }
-                       gen->contents[top].values[index] = value2;
+                       _jit_gen_load_value(gen, desc->reg, desc->other_reg, desc->value);
+                       bind_temporary(gen, desc->reg, desc->other_reg);
                }
        }
-
-       if(pop)
-       {
-               num_values = 0;
-               used_for_temp = 0;
-               age = 0;
-       }
        else
        {
-               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;
-}
-
-/*
- * Drop value from register.
- */
-static void
-free_value(jit_gencode_t gen, jit_value_t value, int reg, int 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);
+#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
-
-       /* Never free global registers. */
-       if(value->has_global_register && value->global_reg == reg)
-       {
-               return;
-       }
-
-       /* Free stack register. */
-       if(IS_STACK_REG(reg) && gen->contents[reg].num_values == 1)
-       {
-               exch_stack_top(gen, reg, 1);
+               {
+                       _jit_gen_load_value(gen, desc->reg, desc->other_reg, desc->value);
+                       bind_value(gen, desc->value, desc->reg, desc->other_reg, 1);
+               }
        }
-
-       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.
- */
+#ifdef JIT_REG_STACK
 static void
-save_value(jit_gencode_t gen, jit_value_t value, int reg, int other_reg, int free)
+move_input_value(jit_gencode_t gen, _jit_regs_t *regs, int index)
 {
-       int stack_start, top;
+       _jit_regdesc_t *desc;
+       int src_reg, dst_reg;
 
 #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("move_input_value(%d)\n", index);
 #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)
-               {
-                       return;
-               }
 
-               if(!value->in_global_register)
-               {
-                       _jit_gen_spill_reg(gen, reg, other_reg, value);
-                       value->in_global_register = 1;
-               }
-               if(free)
-               {
-                       unbind_value(gen, value, reg, other_reg);
-               }
+       desc = &regs->descs[index];
+       if(!desc->value || desc->duplicate || !desc->value->in_register)
+       {
                return;
        }
-
-       /* Take care of constants and values that are already in frame. */
-       if(value->is_constant || value->in_frame)
+       if(!IS_STACK_REG(desc->value->reg))
        {
-               if(free)
-               {
-                       free_value(gen, value, reg, other_reg);
-               }
                return;
        }
 
-       /* Now really save the value into frame. */
-       if(IS_STACK_REG(reg))
-       {
-               /* 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)
-               {
-                       exch_stack_top(gen, reg, 0);
-               }
-
-               if(free && gen->contents[top].num_values == 1)
-               {
-                       _jit_gen_spill_top(gen, top, value, 1);
-                       remap_stack_down(gen, stack_start, top);
-               }
-               else
+       if(desc->copy)
+       {
+               src_reg = desc->stack_reg;
+               if(src_reg < 0)
                {
-                       _jit_gen_spill_top(gen, top, value, 0);
+                       return;
                }
        }
        else
        {
-               _jit_gen_spill_reg(gen, reg, other_reg, value);
+               src_reg = desc->value->reg;
        }
 
-       if(free)
+       if(desc->reg < gen->reg_stack_top)
        {
-               unbind_value(gen, value, reg, other_reg);
+               dst_reg = desc->reg;
+       }
+       else
+       {
+               dst_reg = gen->reg_stack_top - 1;
+       }
+
+       if(src_reg != dst_reg)
+       {
+               if(src_reg != (gen->reg_stack_top - 1))
+               {
+                       exch_stack_top(gen, src_reg, 0);
+               }
+               if(dst_reg != (gen->reg_stack_top - 1))
+               {
+                       exch_stack_top(gen, dst_reg, 0);
+               }
        }
-       value->in_frame = 1;
 }
+#endif
 
-/*
- * Spill regular (non-stack) register.
- */
 static void
-spill_reg(jit_gencode_t gen, _jit_regs_t *regs, int reg)
+abort_input_value(jit_gencode_t gen, _jit_regs_t *regs, int index)
 {
-       int other_reg, index, usage;
-       jit_value_t value;
+       _jit_regdesc_t *desc;
+       int reg, other_reg;
 
 #ifdef JIT_REG_DEBUG
-       printf("spill_reg(reg = %d)\n", reg);
+       printf("abort_input_value(%d)\n", index);
 #endif
 
-       /* 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
+       desc = &regs->descs[index];
+       if(!desc->value || desc->duplicate)
        {
-               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(desc->load && desc->value->in_register)
        {
-               for(index = gen->contents[reg].num_values - 1; index >= 0; --index)
+               reg = desc->value->reg;
+               if(gen->contents[reg].is_long_start)
                {
-                       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);
-                       }
+                       other_reg = OTHER_REG(reg);
                }
-       }
-       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_DEAD) == 0)
+               else
                {
-                       if((usage & VALUE_INPUT) == 0)
-                       {
-                               save_value(gen, value, reg, other_reg, 1);
-                       }
-                       else
-                       {
-                               save_value(gen, value, reg, other_reg, 0);
-                       }
+                       other_reg = -1;
                }
-               else
+               unbind_value(gen, desc->value, reg, other_reg);
+#ifdef JIT_REG_STACK
+               if(IS_STACK_REG(reg))
                {
-                       if((usage & VALUE_INPUT) == 0)
-                       {
-                               free_value(gen, value, reg, other_reg);
-                       }
+                       --(gen->reg_stack_top);
                }
+#endif
        }
 }
 
 static void
-update_age(jit_gencode_t gen, _jit_regdesc_t *desc)
+commit_input_value(jit_gencode_t gen, _jit_regs_t *regs, int index)
 {
+       _jit_regdesc_t *desc;
        int reg, other_reg;
 
-       reg = desc->value->reg;
-       if(gen->contents[reg].is_long_start)
+#ifdef JIT_REG_DEBUG
+       printf("commit_input_value(%d)\n", index);
+#endif
+
+       desc = &regs->descs[index];
+       if(!desc->value || desc->duplicate)
        {
-               other_reg = OTHER_REG(reg);
+               return;
        }
-       else
+
+       if(desc->copy)
        {
-               other_reg = -1;
+#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)
+               {
+                       gen->contents[desc->other_reg].used_for_temp = 0;
+               }
        }
 
-       gen->contents[reg].age = gen->current_age;
-       if(other_reg >= 0)
+       if(desc->kill && desc->value->in_register)
        {
-               gen->contents[other_reg].age = gen->current_age;
+               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
        }
-       ++(gen->current_age);
+
+#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
-save_input_value(jit_gencode_t gen, _jit_regs_t *regs, int index)
+commit_output_value(jit_gencode_t gen, _jit_regs_t *regs)
 {
        _jit_regdesc_t *desc;
-       int reg, other_reg;
 
 #ifdef JIT_REG_DEBUG
-       printf("save_input_value(%d)\n", index);
+       printf("commit_output_value()\n");
 #endif
 
-       desc = &regs->descs[index];
-       if(!(desc->value && desc->value->in_register && desc->save))
+       desc = &regs->descs[0];
+       if(!desc->value)
        {
                return;
        }
 
-       reg = desc->value->reg;
-       if(gen->contents[reg].is_long_start)
-       {
-               other_reg = OTHER_REG(reg);
-       }
-       else
+#ifdef JIT_REG_STACK
+       if(IS_STACK_REG(desc->reg))
        {
-               other_reg = -1;
+               ++(gen->reg_stack_top);
        }
+#endif
+       bind_value(gen, desc->value, desc->reg, desc->other_reg, 0);
 
-       if(desc->thrash)
+       if(!desc->used)
        {
-               save_value(gen, desc->value, reg, other_reg, 1);
+               if(desc->live)
+               {
+                       save_value(gen, desc->value, desc->reg, desc->other_reg, 1);
+               }
+               else
+               {
+                       free_value(gen, desc->value, desc->reg, desc->other_reg, 0);
+               }
        }
-       else
+       else if(desc->kill)
        {
-               save_value(gen, desc->value, reg, other_reg, 0);
+               save_value(gen, desc->value, desc->reg, desc->other_reg, 1);
        }
-}
-
-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("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
+}
 
-       desc = &regs->descs[0];
-       if(!(desc->value && desc->value->in_register))
+/*@
+ * @deftypefun void _jit_regs_lookup (char *name)
+ * Get the pseudo register by its name.
+ * @end deftypefun
+@*/
+int
+_jit_regs_lookup(char *name)
+{
+       int reg;
+       if(name)
        {
-               return;
+               for(reg = 0; reg < JIT_NUM_REGS; reg++)
+               {
+                       if(strcmp(_jit_reg_info[reg].name, name) == 0)
+                       {
+                               return reg;
+                       }
+               }
        }
-       if(desc->value == regs->descs[1].value || desc->value == regs->descs[2].value)
+       return -1;
+}
+
+/*@
+ * @deftypefun int _jit_regs_needs_long_pair (jit_type_t type)
+ * Determine if a type requires a long register pair.
+ * @end deftypefun
+@*/
+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)
        {
-               return;
+               if(type->kind == JIT_TYPE_LONG || type->kind == JIT_TYPE_ULONG)
+               {
+                       return 1;
+               }
        }
+       return 0;
+#else
+       /* We don't register pairs on 64-bit platforms or the interpreter */
+       return 0;
+#endif
+}
 
-       reg = desc->value->reg;
-       if(gen->contents[reg].is_long_start)
+/*@
+ * @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
+@*/
+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))
        {
-               other_reg = OTHER_REG(reg);
+               reg = gen->reg_stack_top - reg;
+               cpu_reg = _jit_reg_info[reg].cpu_reg;
+               other = -1;
+       }
+       else
+#endif
+       {
+               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
+               {
+                       other = -1;
+               }
        }
-       else
+       if(other_reg)
        {
-               other_reg = -1;
+               *other_reg = other;
        }
-
-       free_value(gen, desc->value, reg, other_reg);
+       return cpu_reg;
 }
 
-static void
-load_input_value(jit_gencode_t gen, _jit_regs_t *regs, int index)
+/*@
+ * @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
+@*/
+void _jit_regs_alloc_global(jit_gencode_t gen, jit_function_t func)
 {
-       _jit_regdesc_t *desc;
-
-#ifdef JIT_REG_DEBUG
-       printf("load_input_value(%d)\n", index);
-#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;
 
-       desc = &regs->descs[index];
-       if(!desc->value || desc->duplicate)
+       /* 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(desc->value->has_global_register)
+       /* 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)
        {
-               if(desc->value->in_global_register && desc->value->global_reg == desc->reg)
-               {
-                       return;
-               }
-               if(desc->value->in_register && desc->value->reg == desc->reg)
+               for(reg = 0; reg < JIT_NUM_REGS; ++reg)
                {
-                       update_age(gen, desc);
-                       return;
+                       if((_jit_reg_info[reg].flags &
+                                       (JIT_REG_FIXED | JIT_REG_CALL_USED)) == 0)
+                       {
+                               jit_reg_set_used(gen->permanent, reg);
+                       }
                }
-               _jit_gen_load_value(gen, desc->reg, desc->other_reg, desc->value);
+               return;
        }
-       else if(desc->value->in_register)
+
+       /* 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(desc->value->reg == desc->reg)
+               if(!(block->next))
                {
-                       update_age(gen, desc);
-                       if(IS_STACK_REG(desc->reg))
+                       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))
                        {
-                               desc->stack_reg = desc->reg;
+                               /* 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;
+                               }
                        }
-                       return;
                }
+               block = block->next;
+       }
 
-               if(IS_STACK_REG(desc->reg))
+       /* 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)
                {
-                       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);
+                       --reg;
                }
-               else
+               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_init_for_block (jit_gencode_t gen)
+ * Initialize the register allocation state for a new block.
+ * @end deftypefun
+@*/
+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)
                {
-                       _jit_gen_load_value(gen, desc->reg, desc->other_reg, desc->value);
-                       bind_temporary(gen, desc->reg, desc->other_reg);
+                       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;
                }
+#ifdef JIT_REG_STACK
+               gen->reg_stack_top = JIT_REG_STACK_START;
+#endif
        }
-       else
+       gen->inhibit = jit_regused_init;
+}
+
+/*@
+ * @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
+@*/
+void
+_jit_regs_spill_all(jit_gencode_t gen)
+{
+       int reg;
+
+#ifdef JIT_REG_DEBUG
+       printf("enter _jit_regs_spill_all\n");
+#endif
+
+       for(reg = 0; reg < JIT_NUM_REGS; reg++)
        {
-               if(IS_STACK_REG(desc->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)
                {
-                       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);
+                       continue;
+               }
+
+               /* If this is a stack register, then we need to find the
+                  register that contains the top-most stack position,
+                  because we must spill stack registers from top down.
+                  As we spill each one, something else will become the top */
+#ifdef JIT_REG_STACK
+               if(IS_STACK_REG(reg))
+               {
+                       if(gen->reg_stack_top > JIT_REG_STACK_START)
+                       {
+                               spill_register(gen, gen->reg_stack_top - 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);
+                       spill_register(gen, reg);
                }
        }
-}
-
-static void
-move_input_value(jit_gencode_t gen, _jit_regs_t *regs, int index)
-{
-       _jit_regdesc_t *desc;
-       int src_reg, dst_reg;
 
 #ifdef JIT_REG_DEBUG
-       printf("move_input_value(%d)\n", index);
+       printf("leave _jit_regs_spill_all\n");
 #endif
+}
 
-       desc = &regs->descs[index];
-       if(!desc->value || desc->duplicate || !desc->value->in_register)
+/*@
+ * @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
+@*/
+void
+_jit_regs_set_incoming(jit_gencode_t gen, int reg, jit_value_t value)
+{
+       int other_reg;
+
+       /* Find the other register in a long pair */
+       if(_jit_regs_needs_long_pair(value->type))
        {
-               return;
+               other_reg = OTHER_REG(reg);
        }
-       if(!IS_STACK_REG(desc->value->reg))
+       else
        {
-               return;
+               other_reg = -1;
        }
 
-       if(desc->copy)
+       /* Eject any values that are currently in the register */
+       spill_register(gen, reg);
+       if(other_reg >= 0)
        {
-               src_reg = desc->stack_reg;
-               if(src_reg < 0)
-               {
-                       return;
-               }
+               spill_register(gen, other_reg);
        }
-       else
+
+       /* Record that the value is in "reg", but not in the frame */
+#ifdef JIT_REG_STACK
+       if(IS_STACK_REG(reg))
        {
-               src_reg = desc->value->reg;
+               ++(gen->reg_stack_top);
        }
+#endif
+       bind_value(gen, value, reg, other_reg, 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
+@*/
+void
+_jit_regs_set_outgoing(jit_gencode_t gen, int reg, jit_value_t value)
+{
+       int other_reg;
+
+#ifdef JIT_BACKEND_X86
+       jit_type_t type;
+
+       other_reg = -1;
 
-       if(desc->reg <= regs->current_stack_top)
+       type = jit_type_normalize(value->type);
+       if(type)
        {
-               dst_reg = desc->reg;
+               /* 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)
+               {
+                       /* 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 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)
+#else
+       if(_jit_regs_needs_long_pair(value->type))
        {
-               dst_reg = regs->current_stack_top - 1;
+               other_reg = OTHER_REG(reg);
        }
        else
        {
-               dst_reg = regs->current_stack_top;
+               other_reg = -1;
        }
+#endif
+       if(value->in_register && value->reg == reg)
+       {
+               /* 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))
+               {
+                       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
+@*/
+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 @@ abort_input_value(jit_gencode_t gen, _jit_regs_t *regs, int index)
                        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
+@*/
+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))
-               {
-                       remap_stack_down(gen, regs->stack_start, desc->reg);
-               }
-               gen->contents[desc->reg].used_for_temp = 0;
-               if(desc->other_reg >= 0)
+               reg = value->reg;
+               if(!used_again)
                {
-                       gen->contents[desc->other_reg].used_for_temp = 0;
+                       if(need_pair)
+                       {
+                               other_reg = OTHER_REG(reg);
+                       }
+                       else
+                       {
+                               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++)
+       {
+               if((_jit_reg_info[reg].flags & type) == 0)
                {
-                       other_reg = OTHER_REG(reg);
+                       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)
                {
-                       unbind_value(gen, desc->value, reg, -1);
-                       remap_stack_down(gen, regs->stack_start, reg);
+                       other_reg = OTHER_REG(reg);
+                       if(jit_reg_is_used(gen->inhibit, other_reg))
+                       {
+                               continue;
+                       }
+                       if(jit_reg_is_used(gen->permanent, other_reg))
+                       {
+                               continue;
+                       }
                }
                else
                {
-                       unbind_value(gen, desc->value, reg, other_reg);
+                       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)
-       {
-               return;
+               if(spill_cost < suitable_cost
+                  || (spill_cost == suitable_cost
+                      && spill_cost > 0 && gen->contents[reg].age < suitable_age))
+               {
+                       suitable_reg = reg;
+                       suitable_other_reg = other_reg;
+                       suitable_cost = spill_cost;
+                       suitable_age = gen->contents[reg].age;
+               }
        }
 
-       if(IS_STACK_REG(desc->reg))
-       {
-               bind_value(gen, desc->value, desc->reg, -1, 0);
-               remap_stack_up(gen, regs->stack_start, desc->reg);
-       }
-       else
-       {
-               bind_value(gen, desc->value, desc->reg, desc->other_reg, 0);
-       }
-       if(!desc->used)
+       if(suitable_reg >= 0)
        {
-               if(desc->live)
+               spill_register(gen, suitable_reg);
+               if(suitable_other_reg >= 0)
                {
-                       save_value(gen, desc->value, desc->reg, desc->other_reg, 1);
+                       spill_register(gen, suitable_other_reg);
+               }
+
+               _jit_gen_load_value(gen, suitable_reg, suitable_other_reg, value);
+
+               if(!destroy && !used_again)
+               {
+                       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 @@ _jit_regs_init(jit_gencode_t gen, _jit_regs_t *regs, int flags)
 
        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 @@ _jit_regs_assign(jit_gencode_t gen, _jit_regs_t *regs)
 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 @@ _jit_regs_gen(jit_gencode_t gen, _jit_regs_t *regs)
                        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 @@ _jit_regs_gen(jit_gencode_t gen, _jit_regs_t *regs)
                        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,61 +3312,54 @@ _jit_regs_gen(jit_gencode_t gen, _jit_regs_t *regs)
        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)
+               /* Shuffle the values that are already on the register stack. */
+               if(regs->loaded_stack_count > 0 && !regs->x87_arith)
                {
-                       if(regs->descs[0].value && regs->descs[0].value->in_register)
+                       move_input_value(gen, regs, 1);
+                       move_input_value(gen, regs, 2);
+               }
+
+               /* Load and shuffle the remaining values. */
+               if(regs->reverse_args)
+               {
+                       load_input_value(gen, regs, 2);
+                       move_input_value(gen, regs, 2);
+                       load_input_value(gen, regs, 1);
+                       move_input_value(gen, regs, 1);
+               }
+               else
+               {
+                       if(regs->ternary)
                        {
+                               load_input_value(gen, regs, 0);
                                move_input_value(gen, regs, 0);
-                               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)
-               {
+                       load_input_value(gen, regs, 1);
                        move_input_value(gen, regs, 1);
+                       load_input_value(gen, regs, 2);
                        move_input_value(gen, regs, 2);
                }
        }
-
-       /* Load and shuffle the remaining values. */
-       if(regs->x87_arith && regs->reverse_args)
-       {
-               load_input_value(gen, regs, 2);
-               move_input_value(gen, regs, 2);
-               load_input_value(gen, regs, 1);
-               move_input_value(gen, regs, 1);
-       }
        else
+#endif
        {
+               /* Load flat registers. */
                if(regs->ternary)
                {
                        load_input_value(gen, regs, 0);
-                       move_input_value(gen, regs, 0);
                }
                load_input_value(gen, regs, 1);
-               move_input_value(gen, regs, 1);
                load_input_value(gen, regs, 2);
-               move_input_value(gen, regs, 2);
        }
 
 #ifdef JIT_REG_DEBUG
@@ -4471,12 +3399,14 @@ _jit_regs_commit(jit_gencode_t gen, _jit_regs_t *regs)
        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 @@ _jit_regs_commit(jit_gencode_t gen, _jit_regs_t *regs)
 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 @@ _jit_regs_end(jit_gencode_t gen, _jit_regs_t *regs, unsigned char *inst)
        gen->posn.ptr = inst;
        _jit_regs_commit(gen, regs);
 }
-
-/*@
- * @deftypefun void _jit_regs_lookup (char *name)
- * Get register by name.
- * @end deftypefun
-@*/
-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 55f0323a480077dbd67f6a4aa6150397d6d60c25..ed76751b52ed027c47710599be6500071f74ef49 100644 (file)
 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
  */
 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 @@ typedef struct
        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_value1_other(_jit_regs_t *regs);
 int _jit_regs_value2_other(_jit_regs_t *regs);
 int _jit_regs_scratch(_jit_regs_t *regs, int index);
 
-int _jit_regs_lookup(char *name);
-
 #ifdef __cplusplus
 };
 #endif
index 2d1fca5eead1277213a1951b885bfcd5964f0462..11107b8d3ad2501df282d8bcd3780c711c81796e 100644 (file)
@@ -434,140 +434,6 @@ static int get_temp_reg(int reg1, int reg2, int reg3)
        return X86_EDI;
 }
 
-/*
- * 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.
  */
@@ -769,8 +635,7 @@ void _jit_gen_free_reg(jit_gencode_t gen, int reg,
 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 6d68a3b2a8e89900aa2c58403e4e039b3411a00d..bff1b3a5af8b0abb96ebafc98752bdb62ef3b3c2 100644 (file)
@@ -39,19 +39,21 @@ extern      "C" {
        {"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 2182046f574c57565b3c5a4eea750a086d53cdc7..84ba026bb313da88c90971174ce7afe759d08c7f 100644 (file)
@@ -1344,25 +1344,13 @@ JIT_OP_RETURN:
                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 @@ JIT_OP_RETURN_NFLOAT: unary_note, stack, only
                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 d3050e11ae560aa814b276b25d86412488f9707a..b3eb32f2792867a51b905bdcd07055aae437b7e2 100644 (file)
@@ -70,10 +70,8 @@ typedef struct
 #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 @@ struct jit_regcontents
 {
        /* 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 @@ struct jit_regcontents
           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,13 +147,15 @@ struct jit_gencode
        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
-       void                       *epilog_fixup; /* Fixup list for function epilogs */
-       int                                     stack_changed; /* Stack top changed since entry */
+       void                    *epilog_fixup;  /* Fixup list for function epilogs */
+       int                     stack_changed;  /* Stack top changed since entry */
 };
 
 /*