]> git.unchartedbackwaters.co.uk Git - francis/libjit.git/commitdiff
Implement a simple global register allocation policy, based on usage counts.
authorRhys Weatherley <rweather@southern-storm.com.au>
Wed, 2 Jun 2004 07:17:23 +0000 (07:17 +0000)
committerRhys Weatherley <rweather@southern-storm.com.au>
Wed, 2 Jun 2004 07:17:23 +0000 (07:17 +0000)
15 files changed:
ChangeLog
jit/jit-function.c
jit/jit-insn.c
jit/jit-internal.h
jit/jit-reg-alloc.c
jit/jit-reg-alloc.h
jit/jit-rules-arm.c
jit/jit-rules-arm.h
jit/jit-rules-interp.c
jit/jit-rules-interp.h
jit/jit-rules-x86.c
jit/jit-rules-x86.h
jit/jit-rules.h
jit/jit-value.c
tools/gen-sel-parser.y

index 436fa3c36105137371d326e0d86a23dfdd690d62..992ede1b5e220b4784788e794f25600e445f16ec 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,4 +1,13 @@
 
+2004-06-02  Rhys Weatherley  <rweather@southern-storm.com.au>
+
+       * jit/jit-function.c, jit/jit-insn.c, jit/jit-internal.h,
+       jit/jit-reg-alloc.c, jit/jit-reg-alloc.h, jit/jit-rules-arm.c,
+       jit/jit-rules-arm.h, jit/jit-rules-interp.c, jit/jit-rules-interp.h,
+       jit/jit-rules-x86.c, jit/jit-rules-x86.h, jit/jit-rules.h,
+       jit/jit-value.c, tools/gen-sel-parser.y: implement a simple global
+       register allocation policy, based on usage counts.
+
 2004-06-01  Rhys Weatherley  <rweather@southern-storm.com.au>
 
        * jit/jit-cache.c, jit/jit-elf-read.c, tools/gen-apply.c:
index cdb8a92c2b24669b29fd1b9d8ae9e132f40c26cd..8eef76f9443d0140b2382c54d7571c8790bc5296 100644 (file)
@@ -475,6 +475,7 @@ static void compile_block(jit_gencode_t gen, jit_function_t func,
                                insn->value1->in_register = 0;
                                insn->value1->in_frame = 1;
                                insn->value1->has_frame_offset = 1;
+                               insn->value1->has_global_register = 0;  /* Disable globals */
                        }
                        break;
 
@@ -581,6 +582,9 @@ int jit_function_compile(jit_function_t func)
        /* Compute liveness and "next use" information for this function */
        _jit_function_compute_liveness(func);
 
+       /* Allocate global registers to variables within the function */
+       _jit_regs_alloc_global(&gen, func);
+
        /* We may need to perform output twice, if the first attempt fails
           due to a lack of space in the current method cache page */
        do
index 28bf18f4903c292fa35bb6c5537c50436c66e7cc..3c83e4d9ca913e018d2357aba64341d447c21b02 100644 (file)
@@ -4991,7 +4991,7 @@ jit_value_t jit_insn_call
        jit_insn_t insn;
 
        /* Bail out if there is something wrong with the parameters */
-       if(!func || !jit_func)
+       if(!_jit_function_ensure_builder(func) || !jit_func)
        {
                return 0;
        }
@@ -5143,7 +5143,7 @@ jit_value_t jit_insn_call_indirect
        jit_insn_t insn;
 
        /* Bail out if there is something wrong with the parameters */
-       if(!func || !value || !signature)
+       if(!_jit_function_ensure_builder(func) || !value || !signature)
        {
                return 0;
        }
@@ -5257,7 +5257,7 @@ jit_value_t jit_insn_call_indirect_vtable
        jit_insn_t insn;
 
        /* Bail out if there is something wrong with the parameters */
-       if(!func || !value || !signature)
+       if(!_jit_function_ensure_builder(func) || !value || !signature)
        {
                return 0;
        }
@@ -5366,7 +5366,7 @@ jit_value_t jit_insn_call_native
        jit_insn_t insn;
 
        /* Bail out if there is something wrong with the parameters */
-       if(!func || !native_func || !signature)
+       if(!_jit_function_ensure_builder(func) || !native_func || !signature)
        {
                return 0;
        }
index 92e3a2688a0b073b017ce45671679e7b879881df..ffb21f7679f269d6d5d0e393694d077b75626250 100644 (file)
@@ -195,22 +195,27 @@ struct _jit_value
 {
        jit_block_t                     block;
        jit_type_t                      type;
-       short                           is_temporary : 1;
-       short                           is_local : 1;
-       short                           is_volatile : 1;
-       short                           is_addressable : 1;
-       short                           is_constant : 1;
-       short                           is_nint_constant : 1;
-       short                           has_address : 1;
-       short                           free_address : 1;
-       short                           in_register : 1;
-       short                           in_frame : 1;
-       short                           live : 1;
-       short                           next_use : 1;
-       short                           has_frame_offset : 1;
+       int                                     is_temporary : 1;
+       int                                     is_local : 1;
+       int                                     is_volatile : 1;
+       int                                     is_addressable : 1;
+       int                                     is_constant : 1;
+       int                                     is_nint_constant : 1;
+       int                                     has_address : 1;
+       int                                     free_address : 1;
+       int                                     in_register : 1;
+       int                                     in_frame : 1;
+       int                                     in_global_register : 1;
+       int                                     live : 1;
+       int                                     next_use : 1;
+       int                                     has_frame_offset : 1;
+       int                                     global_candidate : 1;
+       int                                     has_global_register : 1;
        short                           reg;
+       short                           global_reg;
        jit_nint                        address;
        jit_nint                        frame_offset;
+       jit_nuint                       usage_count;
 };
 #define        JIT_INVALID_FRAME_OFFSET        ((jit_nint)0x7FFFFFFF)
 
index 2352484eeea4d41965132e0ae5de3d48b529e6c2..c003095d6074bf3f6c01f9b4883a8a7a0d6d673a 100644 (file)
@@ -252,7 +252,16 @@ static void spill_all_between(jit_gencode_t gen, int first, int last)
                                posn >= 0; --posn)
                        {
                                value = gen->contents[real_reg].values[posn];
-                               if(!(value->in_frame))
+                               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)
                                        {
@@ -503,7 +512,16 @@ static void free_reg_and_spill
                for(posn = gen->contents[reg].num_values - 1; posn >= 0; --posn)
                {
                        value = gen->contents[reg].values[posn];
-                       if(!(value->in_frame))
+                       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)
                                {
@@ -696,7 +714,10 @@ void _jit_regs_set_value
 
        /* Adjust the value to reflect that it is in "reg", and maybe the frame */
        value->in_register = 1;
-       value->in_frame = still_in_frame;
+       if(value->has_global_register)
+               value->in_global_register = still_in_frame;
+       else
+               value->in_frame = still_in_frame;
        value->reg = (short)reg;
 }
 
@@ -817,7 +838,10 @@ static void load_value(jit_gencode_t gen, int reg, int other_reg,
        else
        {
                /* Mark the register as containing the value we have loaded */
-               _jit_regs_set_value(gen, reg, value, value->in_frame);
+               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);
        }
 }
 
@@ -963,7 +987,7 @@ int _jit_regs_load_value
                if(destroy)
                {
                        if(gen->contents[reg].num_values == 1 &&
-                          (value->in_frame || !used_again))
+                          (value->in_frame || value->in_global_register || !used_again))
                        {
                                /* We are the only value in this register, and the
                                   value is duplicated in the frame, or will never
@@ -1026,6 +1050,7 @@ int _jit_regs_dest_value(jit_gencode_t gen, jit_value_t value)
                if(gen->contents[reg].num_values == 1)
                {
                        value->in_frame = 0;
+                       value->in_global_register = 0;
                        return reg;
                }
                free_reg_and_spill(gen, reg, 0, 1);
@@ -1100,7 +1125,7 @@ int _jit_regs_load_to_top(jit_gencode_t gen, jit_value_t value, int used_again,
                if((_jit_reg_info[gen->contents[reg].remap].flags
                                & JIT_REG_START_STACK) != 0)
                {
-                       if(value->in_frame || !used_again)
+                       if(value->in_frame || value->in_global_register || !used_again)
                        {
                                /* Disassociate the value from the register and return */
                                value->in_register = 0;
@@ -1163,8 +1188,8 @@ int _jit_regs_load_to_top_two
                                & JIT_REG_START_STACK) != 0 &&
                   gen->contents[reg].remap == (gen->contents[reg2].remap + 1))
                {
-                       if((value->in_frame || !used_again1) &&
-                          (value2->in_frame || !used_again2))
+                       if((value->in_frame || value->in_global_register || !used_again1) &&
+                          (value2->in_frame || value2->in_global_register || !used_again2))
                        {
                                /* Disassociate the values from the registers and return */
                                free_stack_reg(gen, reg2);
@@ -1235,9 +1260,10 @@ void _jit_regs_load_to_top_three
                   gen->contents[reg].remap == (gen->contents[reg2].remap + 1) &&
                   gen->contents[reg2].remap == (gen->contents[reg3].remap + 1))
                {
-                       if((value->in_frame || !used_again1) &&
-                          (value2->in_frame || !used_again2) &&
-                          (value3->in_frame || !used_again3))
+                       if((value->in_frame || value->in_global_register || !used_again1) &&
+                          (value2->in_frame || value2->in_global_register ||
+                                               !used_again2) &&
+                          (value3->in_frame || value3->in_global_register || !used_again3))
                        {
                                /* Disassociate the values from the registers and return */
                                free_stack_reg(gen, reg);
@@ -1315,6 +1341,7 @@ int _jit_regs_new_top(jit_gencode_t gen, jit_value_t value, int type_reg)
        /* 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;
@@ -1345,3 +1372,91 @@ void _jit_regs_force_out(jit_gencode_t gen, jit_value_t value, int is_dest)
                }
        }
 }
+
+/*
+ * 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;
+       }
+
+       /* Scan all values within the function, looking for the most used.
+          We will replace this with a better allocation strategy later */
+       block = func->builder->value_pool.blocks;
+       num = (int)(func->builder->value_pool.elems_per_block);
+       while(block != 0)
+       {
+               if(!(block->next))
+               {
+                       num = (int)(func->builder->value_pool.elems_in_last);
+               }
+               for(posn = 0; posn < num; ++posn)
+               {
+                       value = (jit_value_t)(block->data + posn *
+                                                                 sizeof(struct _jit_value));
+                       if(value->global_candidate && value->usage_count >= JIT_MIN_USED &&
+                          !(value->is_addressable) && !(value->is_volatile))
+                       {
+                               /* Insert this candidate into the list, ordered on count */
+                               index = 0;
+                               while(index < num_candidates &&
+                                     value->usage_count <= candidates[index]->usage_count)
+                               {
+                                       ++index;
+                               }
+                               while(index < num_candidates)
+                               {
+                                       temp = candidates[index];
+                                       candidates[index] = value;
+                                       value = temp;
+                                       ++index;
+                               }
+                               if(index < JIT_NUM_GLOBAL_REGS)
+                               {
+                                       candidates[num_candidates++] = value;
+                               }
+                       }
+               }
+               block = block->next;
+       }
+
+       /* Allocate registers to the candidates.  We allocate from the top-most
+          register in the allocation order, because some architectures like
+          PPC require global registers to be saved top-down for efficiency */
+       reg = JIT_NUM_REGS - 1;
+       for(index = 0; index < num_candidates; ++index)
+       {
+               while(reg >= 0 && (_jit_reg_info[reg].flags & JIT_REG_GLOBAL) == 0)
+               {
+                       --reg;
+               }
+               candidates[index]->has_global_register = 1;
+               candidates[index]->global_reg = (short)reg;
+               jit_reg_set_used(gen->touched, reg);
+               jit_reg_set_used(gen->permanent, reg);
+       }
+
+#endif
+}
index 01a1c65137cc5f4061294aa392794fdc48c20f6b..cc781bfd73107dbc8a0811f596be7d933a5a3e64 100644 (file)
@@ -55,6 +55,7 @@ void _jit_regs_load_to_top_three
 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);
 
 #ifdef __cplusplus
 };
index 2e7e1cde1958923dec2344421f21da290a95ef9d..63c08bce48180edec4b3cc2c87b6068321e92e01 100644 (file)
@@ -827,4 +827,18 @@ void _jit_gen_end_block(jit_gencode_t gen, jit_block_t block)
        /* Nothing to do here for ARM */
 }
 
+int _jit_gen_is_global_candidate(jit_type_t type)
+{
+       switch(jit_type_remove_tags(type)->kind)
+       {
+               case JIT_TYPE_INT:
+               case JIT_TYPE_UINT:
+               case JIT_TYPE_NINT:
+               case JIT_TYPE_NUINT:
+               case JIT_TYPE_PTR:
+               case JIT_TYPE_SIGNATURE:        return 1;
+       }
+       return 0;
+}
+
 #endif /* JIT_BACKEND_ARM */
index 4ec5f6086ed0a0c810927d223bde66fce2cdddd9..20bd76b567cb428a197e7c17446e0e070c5f02ba 100644 (file)
@@ -55,7 +55,8 @@ extern        "C" {
        {"f1",   1, -1, JIT_REG_FLOAT | JIT_REG_CALL_USED}, \
        {"f2",   2, -1, JIT_REG_FLOAT | JIT_REG_CALL_USED}, \
        {"f3",   3, -1, JIT_REG_FLOAT | JIT_REG_CALL_USED},
-#define        JIT_NUM_REGS    20
+#define        JIT_NUM_REGS            20
+#define        JIT_NUM_GLOBAL_REGS     3
 
 /*
  * Define to 1 if we should always load values into registers
index 7d089e70683da6388953aa558d4fbf04e71d047c..4d7b81f47a7a3f19bb06464386462ff3e703326e 100644 (file)
@@ -128,6 +128,10 @@ This register is a candidate for global register allocation.
 The rule file may also have definitions of the following macros:
 
 @table @code
+@item JIT_NUM_GLOBAL_REGS
+The number of registers that are used for global register allocation.
+Set to zero if global register allocation should not be used.
+
 @item JIT_ALWAYS_REG_REG
 Define this to 1 if arithmetic operations must always be performed
 on registers.  Define this to 0 if register/memory and memory/register
@@ -1669,4 +1673,16 @@ void _jit_gen_end_block(jit_gencode_t gen, jit_block_t block)
        gen->working_area = 0;
 }
 
+/*@
+ * @deftypefun int _jit_gen_is_global_candidate (jit_type_t type)
+ * Determine if @code{type} is a candidate for allocation within
+ * global registers.
+ * @end deftypefun
+@*/
+int _jit_gen_is_global_candidate(jit_type_t type)
+{
+       /* Global register allocation is not used by the interpreter */
+       return 0;
+}
+
 #endif /* JIT_BACKEND_INTERP */
index 8f4505ef40fb7e65147203ffd9965fe26bd48b8e..a6d0215adc9c3a06ac95c450a61c3466f7700b15 100644 (file)
@@ -63,7 +63,8 @@ extern        "C" {
                                JIT_REG_CALL_USED | JIT_REG_IN_STACK}, \
        {"r15", 15, -1, JIT_REG_WORD | JIT_REG_LONG | JIT_REG_FLOAT | \
                                JIT_REG_CALL_USED | JIT_REG_END_STACK | JIT_REG_IN_STACK},
-#define        JIT_NUM_REGS    16
+#define        JIT_NUM_REGS            16
+#define        JIT_NUM_GLOBAL_REGS     0
 
 /*
  * Define to 1 if we should always load values into registers
index 5ef3de97558b05a6560823fbd1090e3534d71d46..86d33e0b4ce515c9d8ed67d9be451438bae0823e 100644 (file)
@@ -904,6 +904,16 @@ void _jit_gen_spill_reg(jit_gencode_t gen, int reg,
        /* Make sure that we have sufficient space */
        jit_cache_setup_output(16);
 
+       /* If the value is associated with a global register, then copy to that */
+       if(value->has_global_register)
+       {
+               reg = _jit_reg_info[reg].cpu_reg;
+               other_reg = _jit_reg_info[value->global_reg].cpu_reg;
+               x86_mov_reg_reg(inst, other_reg, reg, sizeof(void *));
+               jit_cache_end_output();
+               return;
+       }
+
        /* Fix the value in place within the local variable frame */
        _jit_gen_fix_value(value);
 
@@ -1067,6 +1077,13 @@ void _jit_gen_load_value
                        break;
                }
        }
+       else if(value->has_global_register)
+       {
+               /* Load the value out of a global register */
+               x86_mov_reg_reg(inst, _jit_reg_info[reg].cpu_reg,
+                                               _jit_reg_info[value->global_reg].cpu_reg,
+                                               sizeof(void *));
+       }
        else
        {
                /* Fix the position of the value in the stack frame */
@@ -1482,4 +1499,18 @@ void _jit_gen_end_block(jit_gencode_t gen, jit_block_t block)
        /* Nothing to do here for x86 */
 }
 
+int _jit_gen_is_global_candidate(jit_type_t type)
+{
+       switch(jit_type_remove_tags(type)->kind)
+       {
+               case JIT_TYPE_INT:
+               case JIT_TYPE_UINT:
+               case JIT_TYPE_NINT:
+               case JIT_TYPE_NUINT:
+               case JIT_TYPE_PTR:
+               case JIT_TYPE_SIGNATURE:        return 1;
+       }
+       return 0;
+}
+
 #endif /* JIT_BACKEND_X86 */
index c0feb39072d31163acefd2001125a2513fe20c8f..b144f54f49951fa95662aba79ba26bbdde0c8082 100644 (file)
@@ -47,7 +47,8 @@ extern        "C" {
        {"st6", 6, -1, JIT_REG_FLOAT | JIT_REG_CALL_USED | JIT_REG_IN_STACK}, \
        {"st7", 7, -1, JIT_REG_FLOAT | JIT_REG_CALL_USED | JIT_REG_END_STACK | \
                                   JIT_REG_IN_STACK},
-#define        JIT_NUM_REGS    16
+#define        JIT_NUM_REGS            16
+#define        JIT_NUM_GLOBAL_REGS     3
 
 /*
  * Define to 1 if we should always load values into registers
index f23ed9a3724ca6305db3618e0d588ef7c53c938d..f73ab04b079f02f8dd7a55b768929789b428e587 100644 (file)
@@ -191,6 +191,7 @@ void _jit_gen_insn(jit_gencode_t gen, jit_function_t func,
                                   jit_block_t block, jit_insn_t insn);
 void _jit_gen_start_block(jit_gencode_t gen, jit_block_t block);
 void _jit_gen_end_block(jit_gencode_t gen, jit_block_t block);
+int _jit_gen_is_global_candidate(jit_type_t type);
 
 /*
  * Determine the byte number within a "jit_int" where the low
index 7f0db7c4095780c857df08217be0c85b42f18071..b24a31f30bccedf28a0c51a4dfe030db39b8c6bc 100644 (file)
@@ -604,6 +604,7 @@ void jit_value_ref(jit_function_t func, jit_value_t value)
        {
                return;
        }
+       ++(value->usage_count);
        if(value->is_temporary)
        {
                if(value->block->func != func)
@@ -626,6 +627,10 @@ void jit_value_ref(jit_function_t func, jit_value_t value)
                        value->is_temporary = 0;
                        value->is_local = 1;
                        value->live = 1;
+                       if(_jit_gen_is_global_candidate(value->type))
+                       {
+                               value->global_candidate = 1;
+                       }
                }
        }
        else if(value->is_local && value->block->func != func)
index 7c702158c0dfc08ba3c6c12a46c5073aad5259e7..dd6e2c1954067e4dc6a162d4fd96d1075b19720b 100644 (file)
@@ -734,7 +734,10 @@ Rule
                                        printf("\telse\n");
                                        printf("\t{\n");
                                        printf("\t\t_jit_gen_spill_reg(gen, reg, -1, insn->dest);\n");
-                                       printf("\t\tinsn->dest->in_frame = 1;\n");
+                                       printf("\t\tif(insn->dest->has_global_register)\n");
+                                       printf("\t\t\tinsn->dest->in_global_register = 1;\n");
+                                       printf("\t\telse\n");
+                                       printf("\t\t\tinsn->dest->in_frame = 1;\n");
                                        printf("\t\t_jit_regs_free_reg(gen, reg, 1);\n");
                                        printf("\t}\n");
                                }