From 2f09c4538c67fc21b32e124595c4dce10a68fabf Mon Sep 17 00:00:00 2001 From: Aleksey Demakov Date: Sun, 11 Feb 2007 23:28:44 +0000 Subject: [PATCH] more correctly handle compilation restart --- ChangeLog | 12 +++ jit/jit-function.c | 91 ++++++++++++++-- jit/jit-reg-alloc.c | 253 +++++++++++++++++++++++++------------------- jit/jit-reg-alloc.h | 1 - 4 files changed, 241 insertions(+), 116 deletions(-) diff --git a/ChangeLog b/ChangeLog index da57e79..c4e9e84 100644 --- a/ChangeLog +++ b/ChangeLog @@ -3,6 +3,18 @@ * jit/jit-dump.c (jit_dump_function): flush the output stream upon dumping the function. + * jit/jit-function.c (cleanup_on_restart, reset_value): add new + functions to clean up the compilation state on restart. + (compile): replace the code that did cleanup on restart with a call + to cleanup_on_restart() which does this job more thoroughly. + + * jit/jit-reg-alloc.h, jit/jit-reg-alloc.c: remove _jit_regs_abort() + function as the new cleanup-on-restart code makes it superflows. + + * jit/jit-reg-alloc.c (is_register_occupied): add new function; + (clobbers_register, spill_clobbered_register, _jit_regs_gen): fix + a problem that shows up with the new cleanup method. + 2007-02-10 Klaus Treichel * jit/jit-function.c: Use the on-demand compilation driver in diff --git a/jit/jit-function.c b/jit/jit-function.c index 1896fc4..dac32ff 100644 --- a/jit/jit-function.c +++ b/jit/jit-function.c @@ -624,6 +624,85 @@ static void compile_block(jit_gencode_t gen, jit_function_t func, } } +/* + * Reset value on restart. + */ +static void +reset_value(jit_value_t value) +{ + value->reg = -1; + value->in_register = 0; + value->in_global_register = 0; + value->in_frame = 0; +} + +/* + * Clean up the compilation state on restart. + */ +static void +cleanup_on_restart(jit_gencode_t gen, jit_function_t func) +{ + jit_block_t block; + jit_insn_iter_t iter; + jit_insn_t insn; + +#ifdef _JIT_COMPILE_DEBUG + printf("\n*** Restart compilation ***\n\n"); +#endif + + block = 0; + while((block = jit_block_next(func, block)) != 0) + { + /* Clear the block addresses and fixup lists */ + block->address = 0; + block->fixup_list = 0; + block->fixup_absolute_list = 0; + + /* Reset values referred to by block instructions */ + jit_insn_iter_init(&iter, block); + while((insn = jit_insn_iter_next(&iter)) != 0) + { + if(insn->dest && (insn->flags & JIT_INSN_DEST_OTHER_FLAGS) == 0) + { + reset_value(insn->dest); + } + if(insn->value1 && (insn->flags & JIT_INSN_VALUE1_OTHER_FLAGS) == 0) + { + reset_value(insn->value1); + } + if(insn->value2 && (insn->flags & JIT_INSN_VALUE2_OTHER_FLAGS) == 0) + { + reset_value(insn->value2); + } + } + } + + /* Reset values referred to by builder */ + if(func->builder->setjmp_value) + { + reset_value(func->builder->setjmp_value); + } + if(func->builder->parent_frame) + { + reset_value(func->builder->parent_frame); + } + + /* Reset the "touched" registers mask. The first time compilation + might have followed wrong code paths and thus allocated wrong + registers. */ + if(func->builder->has_tail_call) + { + /* For functions with tail calls _jit_regs_alloc_global() + does not allocate any global registers. The "permanent" + mask has all global registers set to prevent their use. */ + gen->touched = jit_regused_init; + } + else + { + gen->touched = gen->permanent; + } +} + /* * Compile a function and return its entry point. */ @@ -764,17 +843,11 @@ compile(jit_function_t func, void **entry_point) /* End the function's output process */ result = _jit_cache_end_method(&(gen.posn)); - /* If we need to restart on a different cache page, then clear - the block addresses and fixup lists */ + /* If we need to restart on a different cache page, then clean up + the compilation state */ if(result == JIT_CACHE_END_RESTART) { - block = 0; - while((block = jit_block_next(func, block)) != 0) - { - block->address = 0; - block->fixup_list = 0; - block->fixup_absolute_list = 0; - } + cleanup_on_restart(&gen, func); } } while(result == JIT_CACHE_END_RESTART); diff --git a/jit/jit-reg-alloc.c b/jit/jit-reg-alloc.c index 2e0960c..5c606dc 100644 --- a/jit/jit-reg-alloc.c +++ b/jit/jit-reg-alloc.c @@ -88,6 +88,8 @@ mostly don't have to worry about it: #define CLOBBER_OTHER_REG 4 #ifdef JIT_REG_DEBUG +#include + static void dump_regs(jit_gencode_t gen, const char *name) { int reg, index; @@ -208,6 +210,9 @@ are_values_equal(_jit_regdesc_t *desc1, _jit_regdesc_t *desc2) return 0; } +/* + * Exchange the content of two value descriptors. + */ static void swap_values(_jit_regdesc_t *desc1, _jit_regdesc_t *desc2) { @@ -366,6 +371,44 @@ is_register_alive(jit_gencode_t gen, _jit_regs_t *regs, int reg) return 0; } +/* + * Check if the register contains any values either dead or alive + * that may need to be evicted from it. + */ +static int +is_register_occupied(jit_gencode_t gen, _jit_regs_t *regs, int reg) +{ + 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); + } + if(gen->contents[reg].num_values) + { + return 1; + } + + return 0; +} + /* * Determine the effect of using a register for a value. This includes the * following: @@ -439,11 +482,11 @@ clobbers_register(jit_gencode_t gen, _jit_regs_t *regs, int index, int reg, int } flags = CLOBBER_NONE; - if(is_register_alive(gen, regs, reg)) + if(is_register_occupied(gen, regs, reg)) { flags |= CLOBBER_REG; } - if(is_register_alive(gen, regs, other_reg)) + if(is_register_occupied(gen, regs, other_reg)) { flags |= CLOBBER_OTHER_REG; } @@ -492,11 +535,11 @@ clobbers_register(jit_gencode_t gen, _jit_regs_t *regs, int index, int reg, int } } - if(is_register_alive(gen, regs, reg)) + if(is_register_occupied(gen, regs, reg)) { flags |= CLOBBER_REG; } - if(is_register_alive(gen, regs, other_reg)) + if(is_register_occupied(gen, regs, other_reg)) { flags |= CLOBBER_OTHER_REG; } @@ -1729,6 +1772,14 @@ bind_value(jit_gencode_t gen, jit_value_t value, int reg, int other_reg, int sti still_in_frame = 0; } +#ifdef JIT_REG_DEBUG + if(gen->contents[reg].num_values == JIT_MAX_REG_VALUES) + { + printf("*** Too many values for one register! ***\n"); + abort(); + } +#endif + gen->contents[reg].values[gen->contents[reg].num_values] = value; ++(gen->contents[reg].num_values); gen->contents[reg].age = gen->current_age; @@ -2073,59 +2124,113 @@ spill_clobbered_register(jit_gencode_t gen, _jit_regs_t *regs, int reg) printf("spill_clobbered_register(reg = %d)\n", reg); #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 - { - 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. */ +#ifdef JIT_REG_STACK + /* For a stack register spill it in two passes. First drop values that + reqiure neither spilling nor a generation of the free instruction. + Then lazily exchange the register with the top and spill or free it + as necessary. This approach might save a exch/free instructions in + certain cases. */ if(IS_STACK_REG(reg)) { for(index = gen->contents[reg].num_values - 1; index >= 0; --index) { + if(gen->contents[reg].num_values == 1) + { + break; + } + value = gen->contents[reg].values[index]; usage = value_usage(regs, value); - if((usage & VALUE_INPUT) == 0 - && ((usage & VALUE_DEAD) != 0 || value->in_frame)) + if((usage & VALUE_INPUT) != 0) { - free_value(gen, value, reg, other_reg, 0); + continue; + } + if((usage & VALUE_DEAD) != 0 || value->in_frame) + { + unbind_value(gen, value, reg, -1); } } - } - 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) + for(index = gen->contents[reg].num_values - 1; index >= 0; --index) { - if((usage & VALUE_INPUT) == 0) + int top; + + value = gen->contents[reg].values[index]; + usage = value_usage(regs, value); + if((usage & VALUE_INPUT) != 0) { - save_value(gen, value, reg, other_reg, 1); + if((usage & VALUE_DEAD) != 0 || value->in_frame) + { + continue; + } + + top = gen->reg_stack_top - 1; + if(reg != top) + { + exch_stack_top(gen, reg, 0); + reg = top; + } + + save_value(gen, value, reg, -1, 0); } else { - save_value(gen, value, reg, other_reg, 0); + top = gen->reg_stack_top - 1; + if(reg != top) + { + exch_stack_top(gen, reg, 0); + reg = top; + } + + if((usage & VALUE_DEAD) != 0 || value->in_frame) + { + free_value(gen, value, reg, -1, 0); + } + else + { + save_value(gen, value, reg, -1, 1); + } } } + } + else +#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 { - if((usage & VALUE_INPUT) == 0) + other_reg = -1; + } + + 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) + { + if((usage & VALUE_INPUT) == 0) + { + save_value(gen, value, reg, other_reg, 1); + } + else + { + save_value(gen, value, reg, other_reg, 0); + } + } + else { - free_value(gen, value, reg, other_reg, 0); + if((usage & VALUE_INPUT) == 0) + { + free_value(gen, value, reg, other_reg, 0); + } } } } @@ -2352,43 +2457,6 @@ move_input_value(jit_gencode_t gen, _jit_regs_t *regs, int index) } #endif -static void -abort_input_value(jit_gencode_t gen, _jit_regs_t *regs, int index) -{ - _jit_regdesc_t *desc; - int reg, other_reg; - -#ifdef JIT_REG_DEBUG - printf("abort_input_value(%d)\n", index); -#endif - - desc = ®s->descs[index]; - if(!desc->value || desc->duplicate) - { - return; - } - - if(desc->load && desc->value->in_register) - { - 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 - } -} - #ifdef JIT_REG_STACK static void pop_input_value(jit_gencode_t gen, _jit_regs_t *regs, int index) @@ -3437,28 +3505,20 @@ _jit_regs_gen(jit_gencode_t gen, _jit_regs_t *regs) if(IS_STACK_REG(reg)) { 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--) + for(; top >= reg && jit_reg_is_used(regs->clobber, top); top--) { spill_clobbered_register(gen, regs, top); /* If an input value is on the top then it stays there - and the top does not change. */ + and the top position does not change. */ if(gen->contents[top].num_values > 0) { break; } } - /* If the top register was not spilled then exchange it with - the current register. */ if(top > reg) { - exch_stack_top(gen, reg, 0); - } - /* Finally spill the register */ - if(top >= JIT_REG_STACK_START) - { - spill_clobbered_register(gen, regs, top); + spill_clobbered_register(gen, regs, reg); } } else @@ -3694,17 +3754,6 @@ _jit_regs_commit(jit_gencode_t gen, _jit_regs_t *regs) #endif } -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); - } -} - unsigned char * _jit_regs_inst_ptr(jit_gencode_t gen, int space) { @@ -3723,8 +3772,6 @@ _jit_regs_inst_ptr(jit_gencode_t gen, int space) unsigned char * _jit_regs_begin(jit_gencode_t gen, _jit_regs_t *regs, int space) { - unsigned char *inst; - if(!_jit_regs_assign(gen, regs)) { return 0; @@ -3734,13 +3781,7 @@ _jit_regs_begin(jit_gencode_t gen, _jit_regs_t *regs, int space) return 0; } - inst = _jit_regs_inst_ptr(gen, space); - if(!inst) - { - _jit_regs_abort(gen, regs); - } - - return inst; + return _jit_regs_inst_ptr(gen, space); } void diff --git a/jit/jit-reg-alloc.h b/jit/jit-reg-alloc.h index 083d753..ea8b524 100644 --- a/jit/jit-reg-alloc.h +++ b/jit/jit-reg-alloc.h @@ -175,7 +175,6 @@ int _jit_regs_gen(jit_gencode_t gen, _jit_regs_t *regs); int _jit_regs_select(_jit_regs_t *regs); #endif void _jit_regs_commit(jit_gencode_t gen, _jit_regs_t *regs); -void _jit_regs_abort(jit_gencode_t gen, _jit_regs_t *regs); int _jit_regs_get_dest(_jit_regs_t *regs); int _jit_regs_get_value1(_jit_regs_t *regs); -- 2.47.3