From af3f8fd9e4ac8747e0ddc732324fa05e2b210c9e Mon Sep 17 00:00:00 2001 From: Rhys Weatherley Date: Sat, 29 May 2004 09:44:51 +0000 Subject: [PATCH] Continue the x86 back end; particularly byte/short stores. --- ChangeLog | 6 ++ jit/jit-insn.c | 3 +- jit/jit-reg-alloc.c | 215 +++++++++++++++++++++++++++--------------- jit/jit-reg-alloc.h | 2 + jit/jit-rules-x86.c | 13 +++ jit/jit-rules-x86.sel | 97 +++++++++++++++++-- 6 files changed, 252 insertions(+), 84 deletions(-) diff --git a/ChangeLog b/ChangeLog index 9de459f..20b4b76 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,10 @@ +2004-05-29 Rhys Weatherley + + * jit/jit-insn.c, jit/jit-reg-alloc.c, jit/jit-reg-alloc.h, + jit/jit-rules-x86.c, jit/jit-rules-x86.sel: continue the + x86 back end; particularly byte/short stores. + 2004-05-27 Rhys Weatherley * tools/gen-apply.c: split "detect_struct_conventions" up a bit diff --git a/jit/jit-insn.c b/jit/jit-insn.c index 457c609..00b97a9 100644 --- a/jit/jit-insn.c +++ b/jit/jit-insn.c @@ -5449,10 +5449,10 @@ jit_value_t jit_insn_call_intrinsic { const1 = jit_value_get_constant(arg1); const2 = jit_value_get_constant(arg2); - return_const.type = descriptor->ptr_result_type; if(return_value) { jit_int result; + return_const.type = descriptor->ptr_result_type; temp_const.un.ptr_value = &return_const.un; apply_args[0] = &temp_const.un; apply_args[1] = &const1.un; @@ -5468,6 +5468,7 @@ jit_value_t jit_insn_call_intrinsic } else { + return_const.type = descriptor->return_type; apply_args[0] = &const1.un; apply_args[1] = &const2.un; jit_apply(signature, intrinsic_func, apply_args, diff --git a/jit/jit-reg-alloc.c b/jit/jit-reg-alloc.c index d3af23a..2352484 100644 --- a/jit/jit-reg-alloc.c +++ b/jit/jit-reg-alloc.c @@ -551,7 +551,7 @@ static void free_reg_and_spill } /*@ - * @deftypefun void _jit_regs_want_reg (jit_gencode_t gen, int reg) + * @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 @@ -821,76 +821,22 @@ static void load_value(jit_gencode_t gen, int reg, int other_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) +/* + * 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, other_reg, type; + 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); - /* If the value is already in a register, then try to use that register */ - if(value->in_register) - { - reg = value->reg; - if(destroy) - { - if(gen->contents[reg].num_values == 1 && - (value->in_frame || !used_again)) - { - /* We are the only value in this register, and the - value is duplicated in the frame, or will never - be used again in this block. In this case, - we can disassociate the register from the value - and just return the register as-is */ - value->in_register = 0; - gen->contents[reg].num_values = 0; - gen->contents[reg].used_for_temp = 1; - gen->contents[reg].age = gen->current_age; - if(need_pair) - { - other_reg = _jit_reg_info[reg].other_reg; - gen->contents[other_reg].used_for_temp = 1; - gen->contents[other_reg].age = gen->current_age; - } - ++(gen->current_age); - return reg; - } - else - { - /* We need to spill the register and then reload it */ - spill_register(gen, reg); - } - } - else - { - gen->contents[reg].age = gen->current_age; - if(need_pair) - { - other_reg = _jit_reg_info[reg].other_reg; - gen->contents[other_reg].age = gen->current_age; - } - ++(gen->current_age); - return reg; - } - } - /* Determine the type of register that we need */ switch(jit_type_normalize(value->type)->kind) { @@ -943,7 +889,6 @@ int _jit_regs_load_value { /* We always load stack values to the top of the stack */ reg = create_stack_reg(gen, reg, 1); - load_value(gen, reg, -1, value, destroy); return reg; } else if(!need_pair) @@ -951,19 +896,17 @@ int _jit_regs_load_value if(gen->contents[reg].num_values == 0 && !(gen->contents[reg].used_for_temp)) { - load_value(gen, reg, -1, value, destroy); return reg; } } else { - other_reg = _jit_reg_info[reg].other_reg; + *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)) + gen->contents[*other_reg].num_values == 0 && + !(gen->contents[*other_reg].used_for_temp)) { - load_value(gen, reg, other_reg, value, destroy); return reg; } } @@ -983,17 +926,114 @@ int _jit_regs_load_value } /* Eject the current contents of the register */ - reg = _jit_regs_want_reg(gen, reg, need_pair); + 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; - /* Load the value into the register */ - if(!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) { - load_value(gen, reg, -1, value, destroy); + reg = value->reg; + if(destroy) + { + if(gen->contents[reg].num_values == 1 && + (value->in_frame || !used_again)) + { + /* We are the only value in this register, and the + value is duplicated in the frame, or will never + be used again in this block. In this case, + we can disassociate the register from the value + and just return the register as-is */ + value->in_register = 0; + gen->contents[reg].num_values = 0; + gen->contents[reg].used_for_temp = 1; + gen->contents[reg].age = gen->current_age; + if(need_pair) + { + other_reg = _jit_reg_info[reg].other_reg; + gen->contents[other_reg].used_for_temp = 1; + gen->contents[other_reg].age = gen->current_age; + } + ++(gen->current_age); + return reg; + } + else + { + /* We need to spill the register and then reload it */ + spill_register(gen, reg); + } + } + else + { + gen->contents[reg].age = gen->current_age; + if(need_pair) + { + other_reg = _jit_reg_info[reg].other_reg; + gen->contents[other_reg].age = gen->current_age; + } + ++(gen->current_age); + return reg; + } } - else + + /* 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) { - load_value(gen, reg, _jit_reg_info[reg].other_reg, value, destroy); + reg = value->reg; + if(gen->contents[reg].num_values == 1) + { + value->in_frame = 0; + return reg; + } + free_reg_and_spill(gen, reg, 0, 1); } + + /* Find a suitable register to hold the destination */ + reg = free_register_for_value(gen, value, &other_reg); + _jit_regs_set_value(gen, reg, value, 0); return reg; } @@ -1282,3 +1322,26 @@ int _jit_regs_new_top(jit_gencode_t gen, jit_value_t value, int type_reg) /* Return the allocated register to the caller */ return reg; } + +/*@ + * @deftypefun void _jit_regs_force_out (jit_gencode_t gen, jit_value_t value, int is_dest) + * If @code{value} is currently in a register, then force its value out + * into the stack frame. The @code{is_dest} flag indicates that the value + * will be a destination, so we don't care about the original value. + * @end deftypefun +@*/ +void _jit_regs_force_out(jit_gencode_t gen, jit_value_t value, int is_dest) +{ + if(value->in_register) + { + if((_jit_reg_info[value->reg].flags & JIT_REG_IN_STACK) == 0) + { + free_reg_and_spill(gen, value->reg, 0, !is_dest); + } + else + { + /* Always do a spill for a stack register */ + _jit_regs_want_reg(gen, value->reg, 0); + } + } +} diff --git a/jit/jit-reg-alloc.h b/jit/jit-reg-alloc.h index b78adcc..01a1c65 100644 --- a/jit/jit-reg-alloc.h +++ b/jit/jit-reg-alloc.h @@ -42,6 +42,7 @@ 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 @@ -53,6 +54,7 @@ void _jit_regs_load_to_top_three 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); #ifdef __cplusplus }; diff --git a/jit/jit-rules-x86.c b/jit/jit-rules-x86.c index 62cb530..adb1574 100644 --- a/jit/jit-rules-x86.c +++ b/jit/jit-rules-x86.c @@ -26,6 +26,7 @@ #include "jit-gen-x86.h" #include "jit-reg-alloc.h" +#include /* * Pseudo register numbers for the x86 registers. These are not the @@ -1400,6 +1401,11 @@ static unsigned char *mov_membase_reg_byte return inst; } +#define TODO() \ + do { \ + fprintf(stderr, "TODO at %s, %d\n", __FILE__, (int)__LINE__); \ + } while (0) + void _jit_gen_insn(jit_gencode_t gen, jit_function_t func, jit_block_t block, jit_insn_t insn) { @@ -1408,6 +1414,13 @@ void _jit_gen_insn(jit_gencode_t gen, jit_function_t func, #define JIT_INCLUDE_RULES #include "jit-rules-x86.slc" #undef JIT_INCLUDE_RULES + + default: + { + fprintf(stderr, "TODO(%x) at %s, %d\n", + (int)(insn->opcode), __FILE__, (int)__LINE__); + } + break; } } diff --git a/jit/jit-rules-x86.sel b/jit/jit-rules-x86.sel index fa8fc6f..ad95ad2 100644 --- a/jit/jit-rules-x86.sel +++ b/jit/jit-rules-x86.sel @@ -548,6 +548,7 @@ JIT_OP_CHECK_NULL: unary_note [reg] -> { /* TODO: won't work in a function with a "try" block */ unsigned char *patch; + TODO(); x86_alu_reg_reg(inst, X86_OR, $1, $1); patch = inst; x86_branch8(inst, X86_CC_NE, 0, 0); @@ -640,6 +641,7 @@ JIT_OP_RETURN_NFLOAT: unary_note, stack, only JIT_OP_RETURN_SMALL_STRUCT: spill_before [] -> { /* TODO: load the structure value into EAX:EDX */ + TODO(); inst = jump_to_epilog(gen, inst, block); } @@ -691,6 +693,7 @@ JIT_OP_SETUP_FOR_SIBLING: spill_before JIT_OP_IMPORT: [] -> { /* TODO */ + TODO(); } /* @@ -715,6 +718,7 @@ JIT_OP_COPY_INT: unary JIT_OP_COPY_LONG: spill_before [] -> { /* TODO */ + TODO(); } JIT_OP_COPY_FLOAT32: unary @@ -726,25 +730,101 @@ JIT_OP_COPY_FLOAT64: unary JIT_OP_COPY_NFLOAT: unary [freg] -> {} -JIT_OP_COPY_STRUCT: +JIT_OP_COPY_STRUCT: manual [] -> { /* TODO */ + TODO(); } -JIT_OP_COPY_STORE_BYTE: +JIT_OP_COPY_STORE_BYTE: manual [] -> { - /* TODO */ + unsigned char *inst; + int reg; + _jit_regs_force_out(gen, insn->dest, 1); + _jit_gen_fix_value(insn->dest); + if(!(insn->value1->is_constant)) + { + reg = _jit_regs_load_value + (gen, insn->value1, 0, + (insn->flags & (JIT_INSN_VALUE1_NEXT_USE | + JIT_INSN_VALUE1_LIVE))); + inst = gen->posn.ptr; + if(!jit_cache_check_for_n(&(gen->posn), 32)) + { + jit_cache_mark_full(&(gen->posn)); + return; + } + inst = mov_membase_reg_byte + (inst, X86_EBP, insn->dest->frame_offset, + _jit_reg_info[reg].cpu_reg); + gen->posn.ptr = inst; + } + else + { + inst = gen->posn.ptr; + if(!jit_cache_check_for_n(&(gen->posn), 32)) + { + jit_cache_mark_full(&(gen->posn)); + return; + } + x86_mov_membase_imm(inst, X86_EBP, insn->dest->frame_offset, + insn->value1->address, 1); + gen->posn.ptr = inst; + } } -JIT_OP_COPY_STORE_SHORT: +JIT_OP_COPY_STORE_SHORT: manual [] -> { - /* TODO */ + unsigned char *inst; + int reg; + _jit_regs_force_out(gen, insn->dest, 1); + _jit_gen_fix_value(insn->dest); + if(!(insn->value1->is_constant)) + { + reg = _jit_regs_load_value + (gen, insn->value1, 0, + (insn->flags & (JIT_INSN_VALUE1_NEXT_USE | + JIT_INSN_VALUE1_LIVE))); + inst = gen->posn.ptr; + if(!jit_cache_check_for_n(&(gen->posn), 32)) + { + jit_cache_mark_full(&(gen->posn)); + return; + } + x86_mov_membase_reg(inst, X86_EBP, insn->dest->frame_offset, + _jit_reg_info[reg].cpu_reg, 2); + gen->posn.ptr = inst; + } + else + { + inst = gen->posn.ptr; + if(!jit_cache_check_for_n(&(gen->posn), 32)) + { + jit_cache_mark_full(&(gen->posn)); + return; + } + x86_mov_membase_imm(inst, X86_EBP, insn->dest->frame_offset, + insn->value1->address, 2); + gen->posn.ptr = inst; + } } -JIT_OP_ADDRESS_OF: +JIT_OP_ADDRESS_OF: manual [] -> { + unsigned char *inst; + int reg; + _jit_regs_force_out(gen, insn->value1, 0); _jit_gen_fix_value(insn->value1); - /* TODO: get a register to hold the result */ + inst = gen->posn.ptr; + if(!jit_cache_check_for_n(&(gen->posn), 32)) + { + jit_cache_mark_full(&(gen->posn)); + return; + } + reg = _jit_regs_dest_value(gen, insn->dest); + reg = _jit_reg_info[reg].cpu_reg; + x86_lea_membase(inst, reg, X86_EBP, insn->value1->frame_offset); + gen->posn.ptr = inst; } /* @@ -838,6 +918,7 @@ JIT_OP_PUSH_NFLOAT: unary_note JIT_OP_PUSH_STRUCT: unary_note [reg] -> { /* TODO */ + TODO(); } JIT_OP_POP_STACK: @@ -1037,6 +1118,7 @@ JIT_OP_LOAD_RELATIVE_NFLOAT: manual JIT_OP_LOAD_RELATIVE_STRUCT: manual [] -> { /* TODO */ + TODO(); } JIT_OP_STORE_RELATIVE_BYTE: manual @@ -1339,6 +1421,7 @@ JIT_OP_STORE_RELATIVE_NFLOAT: manual JIT_OP_STORE_RELATIVE_STRUCT: manual [] -> { /* TODO */ + TODO(); } JIT_OP_ADD_RELATIVE: unary -- 2.47.3