From: Aleksey Demakov Date: Fri, 16 Jun 2006 17:53:51 +0000 (+0000) Subject: Extend register allocator to allow separate specification of the destination X-Git-Tag: before.move.to.git~231 X-Git-Url: https://git.unchartedbackwaters.co.uk/w/?a=commitdiff_plain;h=8d1f04f894333fc2bcb8f9eaaf4b1bf6fe1332ea;p=francis%2Flibjit.git Extend register allocator to allow separate specification of the destination register. Take advantage of this for some x86 rules. Tweak the allocator's API. --- diff --git a/ChangeLog b/ChangeLog index e25f6ae..6958349 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,19 @@ +2006-06-17 Aleksey Demakov + + * jit/jit-reg-alloc.h, jit/jit-reg-alloc.c: implement support of the + JIT_REGS_FREE_DEST flag for 3-argument instructions. Tweak reg alloc + API. + + * tools/gen-rules-parser.y: adjust for reg alloc API changes. Use + '$0' pattern element to refer to destination register in 3-argument + instructions. + + * jit/jit-rules-x86.ins: rewrite JIT_OP_IDIV, JIT_OP_IDIV_UN, + JIT_OP_IREM, JIT_OP_IREM_UN, JIT_OP_ADDRESS_OF_LABEL, + JIT_OP_LOAD_RELATIVE_FLOAT32, JIT_OP_LOAD_RELATIVE_FLOAT32, + JIT_OP_LOAD_RELATIVE_NFLOAT, JIT_OP_LOAD_ELEMENT_FLOAT32, + JIT_OP_LOAD_ELEMENT_FLOAT64, JIT_OP_LOAD_ELEMENT_NFLOAT rules. + 2006-06-16 Aleksey Demakov * jit/jit-rules-x86.sel, jit/jit-rules-x86.ins: fix JIT_OP_IDIV and diff --git a/jit/jit-reg-alloc.c b/jit/jit-reg-alloc.c index 3bb167e..67e480c 100644 --- a/jit/jit-reg-alloc.c +++ b/jit/jit-reg-alloc.c @@ -1662,9 +1662,15 @@ void _jit_regs_get_reg_pair(jit_gencode_t gen, int not_this1, int not_this2, #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 -#define ALLOW_CLOBBER_GLOBAL 1 +#ifdef JIT_BACKEND_X86 +# define ALLOW_CLOBBER_GLOBAL 1 +#else +# define ALLOW_CLOBBER_GLOBAL 0 +#endif /* Value usage flags. */ #define VALUE_INPUT 1 @@ -1750,7 +1756,7 @@ get_register_type(jit_value_t value, int need_pair) static int are_values_equal(_jit_regdesc_t *desc1, _jit_regdesc_t *desc2) { - if(desc1->value && desc2->value) + if(desc1 && desc2 && desc1->value && desc2->value) { if(desc1->value == desc2->value) { @@ -1766,11 +1772,40 @@ are_values_equal(_jit_regdesc_t *desc1, _jit_regdesc_t *desc2) /* - * Check if the value is used in and after the current instruction. + * 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. * - * The value is dead if it is the output value of the instruction and hence - * just about to be recomputed or if it is one of the input values and its - * usage flags are not set. Otherwise the value is alive. + * 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) @@ -1867,9 +1902,14 @@ is_register_alive(jit_gencode_t gen, _jit_regs_t *regs, int reg) } /* - * Determine the effect of assigning the value to a register. It finds out - * if the old register contents is clobbered and so needs to be spilled and - * if the newly assigned value will be clobbered by the instruction. + * Determine the effect of assigning a value to a register on the values + * the register contains. The following factors are taken into account: + for + * the instruction + *. It + * checks if the register contains any other values that might be clobbered + * by using the register or if the value in question is clobbered itself by + * the instruction. */ static int clobbers_register(jit_gencode_t gen, _jit_regs_t *regs, int index, int reg, int other_reg) @@ -1903,7 +1943,11 @@ clobbers_register(jit_gencode_t gen, _jit_regs_t *regs, int index, int reg, int else { /* find out the input value that is going to be overwritten by the output */ - if(!regs->descs[2].value) + if(regs->free_dest) + { + out_index = 0; + } + else if(!regs->descs[2].value) { /* a unary op */ out_index = 1; @@ -1953,13 +1997,17 @@ clobbers_register(jit_gencode_t gen, _jit_regs_t *regs, int index, int reg, int } } - /* does input value clobber the register? */ + /* is input value clobbered? */ if(regs->descs[index].clobber) { clobber = 1; } - if(!clobber) + if(clobber) + { + flags = CLOBBER_INPUT_VALUE; + } + else { if(regs->descs[index].value->has_global_register && regs->descs[index].value->global_reg == reg) @@ -1971,12 +2019,7 @@ clobbers_register(jit_gencode_t gen, _jit_regs_t *regs, int index, int reg, int { return CLOBBER_NONE; } - } - - flags = CLOBBER_NONE; - if(clobber) - { - flags |= CLOBBER_INPUT_VALUE; + flags = CLOBBER_NONE; } if(is_alive) { @@ -1990,31 +2033,24 @@ clobbers_register(jit_gencode_t gen, _jit_regs_t *regs, int index, int reg, int } /* - * Set assigned and clobber flags for a register. + * Assign scratch register. */ static void -set_register_flags( - jit_gencode_t gen, - _jit_regs_t *regs, - int reg, - int clobber_reg, - int clobber_input) +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); - if(clobber_reg) - { - jit_reg_set_used(regs->spill, reg); - } - if(clobber_input) - { - jit_reg_set_used(regs->clobber, reg); - } } } +/* + * Initialize value descriptor. + */ static void init_regdesc(_jit_regs_t *regs, int index) { @@ -2031,6 +2067,7 @@ init_regdesc(_jit_regs_t *regs, int index) desc->clobber = 0; desc->early_clobber = 0; desc->duplicate = 0; + desc->thrash = 0; desc->save = 0; desc->load = 0; desc->copy = 0; @@ -2038,12 +2075,12 @@ init_regdesc(_jit_regs_t *regs, int index) } /* - * Initialize register descriptor. + * 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; + _jit_regdesc_t *desc; desc = ®s->descs[index]; desc->value = value; @@ -2064,40 +2101,38 @@ set_regdesc_value(_jit_regs_t *regs, int index, jit_value_t value, int flags, in } /* - * Set assigned and clobber flags for the register descriptor. + * 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 clobber; - if(reg >= 0) { regs->descs[index].reg = reg; regs->descs[index].other_reg = other_reg; - clobber = clobbers_register(gen, regs, index, reg, other_reg); - set_register_flags(gen, regs, reg, - (clobber & CLOBBER_REG), - (clobber & CLOBBER_INPUT_VALUE)); + jit_reg_set_used(gen->touched, reg); + jit_reg_set_used(regs->assigned, reg); if(other_reg >= 0) { - set_register_flags(gen, regs, other_reg, - (clobber & CLOBBER_OTHER_REG), - (clobber & CLOBBER_INPUT_VALUE)); + jit_reg_set_used(gen->touched, other_reg); + jit_reg_set_used(regs->assigned, other_reg); } } } +/* + * Determine value flags. + */ static int -collect_register_info(jit_gencode_t gen, _jit_regs_t *regs, int index) +set_regdesc_flags(jit_gencode_t gen, _jit_regs_t *regs, int index) { - _jit_regdesc_t *desc; + _jit_regdesc_t *desc; int reg, other_reg; - int stack_start; + int clobber, stack_start; #ifdef JIT_REG_DEBUG - printf("collect_register_info(index = %d)\n", index); + printf("set_regdesc_flags(index = %d)\n", index); #endif desc = ®s->descs[index]; @@ -2106,6 +2141,7 @@ collect_register_info(jit_gencode_t gen, _jit_regs_t *regs, int index) return 1; } + /* Find the registers the value is already in (if any). */ if(desc->value->in_register) { reg = desc->value->reg; @@ -2124,20 +2160,94 @@ collect_register_info(jit_gencode_t gen, _jit_regs_t *regs, int index) 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_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); + } + + /* 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) + { + 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))) + { + if(regs->ternary) + { + if(!are_values_equal(desc, ®s->descs[0])) + { + desc->thrash = 1; + } + } + else + { + if(desc->value != regs->descs[0].value) + { + clobber |= CLOBBER_INPUT_VALUE; + } + } + } + } + if(index != 1 && !are_values_equal(desc, ®s->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, ®s->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 - && !(desc->value->in_register && reg == desc->reg)) + && !(reg >= 0 && reg == desc->reg)) { desc->copy = 1; } } else { - if(!desc->value->in_register) + if(reg < 0) { desc->load = 1; } @@ -2154,13 +2264,11 @@ collect_register_info(jit_gencode_t gen, _jit_regs_t *regs, int index) { desc->kill = 1; } - else if(desc->value->in_register) + else if(reg >= 0) { if(desc->used) { - if(jit_reg_is_used(regs->clobber, reg) - || (other_reg >= 0 - && jit_reg_is_used(regs->clobber, other_reg))) + if(!desc->copy && (clobber & CLOBBER_INPUT_VALUE) != 0) { desc->save = 1; desc->kill = 1; @@ -2179,9 +2287,7 @@ collect_register_info(jit_gencode_t gen, _jit_regs_t *regs, int index) { if(desc->used) { - if(jit_reg_is_used(regs->clobber, desc->reg) - || (desc->other_reg >= 0 - && jit_reg_is_used(regs->clobber, desc->other_reg))) + if((clobber & CLOBBER_INPUT_VALUE) != 0) { desc->kill = 1; } @@ -2231,6 +2337,7 @@ collect_register_info(jit_gencode_t gen, _jit_regs_t *regs, int index) 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); @@ -2241,6 +2348,7 @@ collect_register_info(jit_gencode_t gen, _jit_regs_t *regs, int index) 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); @@ -2251,68 +2359,134 @@ collect_register_info(jit_gencode_t gen, _jit_regs_t *regs, int index) } /* - * To avoid circular movements of input values in place of each other - * check if the current value overwrites any of the others. + * Check to see if loading one input value into the given register + * clobbers any other input values. */ static int -thrashes_register(jit_gencode_t gen, _jit_regs_t *regs, - _jit_regdesc_t *desc, int reg, int other_reg) +thrashes_register(jit_gencode_t gen, _jit_regs_t *regs, int index, int reg, int other_reg) { + _jit_regdesc_t *desc; int reg2, other_reg2; - if(regs->ternary && regs->descs[0].value && regs->descs[0].value->in_register - && !(desc && are_values_equal(®s->descs[0], desc))) + + if(index < 0) + { + desc = 0; + } + else { - reg2 = regs->descs[0].value->reg; - if(reg2 == reg || reg2 == other_reg) + if(index == 0 && !regs->ternary) + { + return 0; + } + desc = ®s->descs[index]; + if(!desc->value) + { + return 0; + } + } + + if(index != 0 && regs->ternary && regs->descs[0].value) + { + if(!(desc && regs->descs[0].value == desc->value) + && regs->descs[0].value->has_global_register + && regs->descs[0].value->global_reg == reg) { return 1; } - if(gen->contents[reg2].is_long_start) + if(regs->descs[0].value->in_register + && !are_values_equal(®s->descs[0], desc)) { - other_reg2 = OTHER_REG(reg2); - if(other_reg2 == reg /*|| other_reg2 == other_reg*/) + reg2 = regs->descs[0].value->reg; + if(reg2 == reg || reg2 == other_reg) { return 1; } + if(gen->contents[reg2].is_long_start) + { + other_reg2 = OTHER_REG(reg2); + if(other_reg2 == reg /*|| other_reg2 == other_reg*/) + { + return 1; + } + } } } - if(regs->descs[1].value && regs->descs[1].value->in_register - && !(desc && are_values_equal(®s->descs[1], desc))) + if(index != 1 && regs->descs[1].value) { - reg2 = regs->descs[1].value->reg; - if(reg2 == reg || reg2 == other_reg) + if(!(desc && regs->descs[1].value == desc->value) + && regs->descs[1].value->has_global_register + && regs->descs[1].value->global_reg == reg) { return 1; } - if(gen->contents[reg2].is_long_start) + if(regs->descs[1].value->in_register + && !are_values_equal(®s->descs[1], desc)) { - other_reg2 = OTHER_REG(reg2); - if(other_reg2 == reg /*|| other_reg2 == other_reg*/) + reg2 = regs->descs[1].value->reg; + if(reg2 == reg || reg2 == other_reg) { return 1; } + if(gen->contents[reg2].is_long_start) + { + other_reg2 = OTHER_REG(reg2); + if(other_reg2 == reg /*|| other_reg2 == other_reg*/) + { + return 1; + } + } } } - if(regs->descs[2].value && regs->descs[2].value->in_register - && !(desc && are_values_equal(®s->descs[2], desc))) + if(index != 2 && regs->descs[2].value) { - reg2 = regs->descs[2].value->reg; - if(reg2 == reg || reg2 == other_reg) + if(!(desc && regs->descs[2].value == desc->value) + && regs->descs[2].value->has_global_register + && regs->descs[2].value->global_reg == reg) { return 1; } - if(gen->contents[reg2].is_long_start) + if(regs->descs[2].value->in_register + && !are_values_equal(®s->descs[2], desc)) { - other_reg2 = OTHER_REG(reg2); - if(other_reg2 == reg /*|| other_reg2 == other_reg*/) + reg2 = regs->descs[2].value->reg; + if(reg2 == reg || reg2 == other_reg) { return 1; } + if(gen->contents[reg2].is_long_start) + { + other_reg2 = OTHER_REG(reg2); + if(other_reg2 == reg /*|| other_reg2 == other_reg*/) + { + return 1; + } + } } } return 0; } +/* + * 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) { @@ -2379,16 +2553,24 @@ compute_spill_cost(jit_gencode_t gen, _jit_regs_t *regs, int reg, int other_reg) } if(value->has_global_register) { - if(!value->in_global_register) + if(value->in_global_register) { - cost += 1; + cost += COST_SPILL_CLEAN_GLOBAL; + } + else + { + cost += COST_SPILL_DIRTY_GLOBAL; } } else { - if(!value->in_frame) + if(value->in_frame) + { + cost += COST_SPILL_CLEAN; + } + else { - cost += 10; + cost += COST_SPILL_DIRTY; } } } @@ -2445,17 +2627,19 @@ compute_spill_cost(jit_gencode_t gen, _jit_regs_t *regs, int reg, int other_reg) * */ static int -use_cheapest_register(jit_gencode_t gen, _jit_regs_t *regs, int index, jit_regused_t regset) +use_cheapest_register(jit_gencode_t gen, _jit_regs_t *regs, int index, jit_regused_t allowed) { _jit_regdesc_t *desc; - int output; - int type; - int need_pair; + _jit_regdesc_t *desc2; + _jit_regdesc_t *desc3; + int is_output, output_index; + int type, need_pair; int reg, other_reg; int cost, copy_cost; int suitable_reg; int suitable_cost; int suitable_age; + int clobber; if(index >= 0) { @@ -2464,7 +2648,25 @@ use_cheapest_register(jit_gencode_t gen, _jit_regs_t *regs, int index, jit_regus { return -1; } - output = (index == 0 && !regs->ternary); + + if(regs->ternary || regs->descs[0].value == 0) + { + is_output = 0; + output_index = 0; + } + else + { + is_output = (index == 0); + if(regs->free_dest) + { + output_index = 0; + } + else + { + output_index = 1 + (regs->reverse_dest ^ regs->reverse_args); + } + } + need_pair = _jit_regs_needs_long_pair(desc->value->type); type = get_register_type(desc->value, need_pair); if(!type) @@ -2475,7 +2677,8 @@ use_cheapest_register(jit_gencode_t gen, _jit_regs_t *regs, int index, jit_regus else { desc = 0; - output = 0; + is_output = 0; + output_index = 0; need_pair = 0; type = JIT_REG_WORD; } @@ -2489,8 +2692,7 @@ use_cheapest_register(jit_gencode_t gen, _jit_regs_t *regs, int index, jit_regus { continue; } - - if(!jit_reg_is_used(regset, reg) + if(!jit_reg_is_used(allowed, reg) || jit_reg_is_used(gen->inhibit, reg) || jit_reg_is_used(regs->assigned, reg)) { @@ -2503,125 +2705,122 @@ use_cheapest_register(jit_gencode_t gen, _jit_regs_t *regs, int index, jit_regus { continue; } - else if(thrashes_register(gen, regs, desc, reg, -1)) + else if(thrashes_register(gen, regs, index, reg, -1)) { continue; } - copy_cost = 0; cost = compute_spill_cost(gen, regs, reg, -1); + copy_cost = 0; } - else if(desc->value->has_global_register) + else { - if(reg == desc->value->global_reg) + if(need_pair) { - if(clobbers_register(gen, regs, index, reg, -1)) + other_reg = OTHER_REG(reg); + if(jit_reg_is_used(gen->inhibit, other_reg) + || jit_reg_is_used(regs->assigned, other_reg)) { continue; } - copy_cost = ((output | desc->value->in_global_register) == 0); - cost = 0; } - else if(jit_reg_is_used(gen->permanent, reg)) - { - continue; - } - else if(thrashes_register(gen, regs, desc, reg, -1)) + else { - continue; + other_reg = -1; } - else if(desc->value->in_register && reg == desc->value->reg) + + clobber = clobbers_register(gen, regs, index, reg, other_reg); + if((clobber & ~CLOBBER_INPUT_VALUE) != 0) { - copy_cost = ((output | desc->value->in_global_register) != 0); - if(clobbers_register(gen, regs, index, reg, -1)) + if(jit_reg_is_used(gen->permanent, reg)) + { + continue; + } +#if !ALLOW_LONGS_USE_GLOBAL + if(other_reg >= 0 && jit_reg_is_used(gen->permanent, other_reg)) { - cost = compute_spill_cost(gen, regs, reg, -1); + continue; } - else +#endif + if(jit_reg_is_used(regs->clobber, reg) + || (other_reg >= 0 && jit_reg_is_used(regs->clobber, other_reg))) { cost = 0; } + else + { + cost = compute_spill_cost(gen, regs, reg, other_reg); + } +#if ALLOW_LONGS_USE_GLOBAL + if(other_reg >= 0 && jit_reg_is_used(gen->permanent, other_reg)) + { + cost += COST_CLOBBER_GLOBAL; + } +#endif } else { - copy_cost = 1; - cost = compute_spill_cost(gen, regs, reg, -1); - } - } - else - { - if(jit_reg_is_used(gen->permanent, reg)) - { - continue; + cost = 0; } - if(need_pair) + if(thrashes_register(gen, regs, + is_output ? output_index : index, + reg, other_reg)) { - other_reg = OTHER_REG(reg); - - if(jit_reg_is_used(gen->inhibit, other_reg) - || jit_reg_is_used(regs->assigned, other_reg)) + if(jit_reg_is_used(gen->permanent, reg)) { continue; } -#if !ALLOW_CLOBBER_GLOBAL - if(jit_reg_is_used(gen->permanent, other_reg)) + if(other_reg >= 0 && jit_reg_is_used(gen->permanent, other_reg)) { continue; } -#endif - } - else - { - other_reg = -1; + cost += COST_THRASH; + if(other_reg >= 0) + { + cost += COST_THRASH; + } } - if(thrashes_register(gen, regs, desc, reg, other_reg)) + if(is_output) { - continue; + if(output_index && regs->descs[output_index].value) + { + desc2 = ®s->descs[output_index]; + } + else + { + desc2 = 0; + } + desc3 = ®s->descs[0]; } - if(desc->value->in_register) + else { - if(reg == desc->value->reg) + desc2 = desc; + if(output_index && index == output_index) { - if(clobbers_register(gen, regs, index, reg, other_reg) - && !(jit_reg_is_used(regs->clobber, reg) - || (other_reg >= 0 - && jit_reg_is_used(regs->clobber, other_reg)))) - { - copy_cost = 0; - cost = compute_spill_cost(gen, regs, reg, other_reg); - } - else - { - copy_cost = 0; - cost = 0; - } + desc3 = ®s->descs[0]; } else { - copy_cost = 1; - cost = compute_spill_cost(gen, regs, reg, other_reg); + desc3 = desc; } } - else + if(!desc2 + || (desc2->value->in_global_register && desc2->value->global_reg == reg) + || (desc2->value->in_register && desc2->value->reg == reg)) { copy_cost = 0; - 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)) + else { - cost += COST_CLOBBER_GLOBAL; + copy_cost = COST_COPY; + } + if(desc3->value->has_global_register && desc3->value->global_reg != reg) + { + cost += COST_GLOBAL_BIAS; } -#endif } -#if COST_COPY != 1 - if(copy_cost) - { - copy_cost = COST_COPY; - } -#endif if((cost + copy_cost) < suitable_cost || (cost > 0 && (cost + copy_cost) == suitable_cost && gen->contents[reg].age < suitable_age)) @@ -2634,24 +2833,17 @@ use_cheapest_register(jit_gencode_t gen, _jit_regs_t *regs, int index, jit_regus } reg = suitable_reg; - if(reg >= 0) + if(desc && reg >= 0) { - if(desc) + if(need_pair) { - if(need_pair) - { - other_reg = OTHER_REG(reg); - } - else - { - other_reg = -1; - } - set_regdesc_register(gen, regs, index, reg, other_reg); + other_reg = OTHER_REG(reg); } else { - set_register_flags(gen, regs, reg, 1, 0); + other_reg = -1; } + set_regdesc_register(gen, regs, index, reg, other_reg); } return reg; @@ -2694,7 +2886,7 @@ select_order(jit_gencode_t gen, _jit_regs_t *regs) int keep1, keep2; int out_index; - if(regs->ternary || !(regs->commutative || regs->x87_arith)) + if(regs->ternary || regs->free_dest || !(regs->commutative || regs->x87_arith)) { /* Bail out on ternary or non-commutative and non-x87 instruction. */ return; @@ -2711,7 +2903,7 @@ select_order(jit_gencode_t gen, _jit_regs_t *regs) } /* Determine if we might want to keep either of input values - in registers after the operation completion. */ + in registers after the instruction completion. */ if(regs->clobber_all) { keep1 = 0; @@ -3003,6 +3195,11 @@ bind_value(jit_gencode_t gen, jit_value_t value, int reg, int other_reg, int sti 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; @@ -3397,7 +3594,14 @@ save_input_value(jit_gencode_t gen, _jit_regs_t *regs, int index) other_reg = -1; } - save_value(gen, desc->value, reg, other_reg, 0); + if(desc->thrash) + { + save_value(gen, desc->value, reg, other_reg, 1); + } + else + { + save_value(gen, desc->value, reg, other_reg, 0); + } } static void @@ -3721,7 +3925,7 @@ commit_output_value(jit_gencode_t gen, _jit_regs_t *regs) } void -_jit_regs_init(_jit_regs_t *regs, int flags) +_jit_regs_init(jit_gencode_t gen, _jit_regs_t *regs, int flags) { int index; @@ -3750,9 +3954,22 @@ _jit_regs_init(_jit_regs_t *regs, int flags) } regs->num_scratch = 0; - regs->assigned = jit_regused_init; + /* Set clobber flags. */ regs->clobber = jit_regused_init; - regs->spill = jit_regused_init; + if(regs->clobber_all) + { + for(index = 0; index < JIT_NUM_REGS; index++) + { + if((_jit_reg_info[index].flags & JIT_REG_FIXED) + || jit_reg_is_used(gen->permanent, index)) + { + continue; + } + jit_reg_set_used(regs->clobber, index); + } + } + + regs->assigned = jit_regused_init; regs->stack_start = -1; regs->current_stack_top = 0; @@ -3794,39 +4011,55 @@ _jit_regs_init_value2(_jit_regs_t *regs, jit_insn_t insn, int flags) } void -_jit_regs_set_dest(_jit_regs_t *regs, int reg, int other_reg) +_jit_regs_set_dest(jit_gencode_t gen, _jit_regs_t *regs, int reg, int other_reg) { - regs->descs[0].reg = reg; - regs->descs[0].other_reg = other_reg; + if(reg >= 0 && !IS_STACK_REG(reg)) + { + set_regdesc_register(gen, regs, 0, reg, other_reg); + } } void -_jit_regs_set_value1(_jit_regs_t *regs, int reg, int other_reg) +_jit_regs_set_value1(jit_gencode_t gen, _jit_regs_t *regs, int reg, int other_reg) { - regs->descs[1].reg = reg; - regs->descs[1].other_reg = other_reg; + if(reg >= 0 && !IS_STACK_REG(reg)) + { + set_regdesc_register(gen, regs, 1, reg, other_reg); + } } void -_jit_regs_set_value2(_jit_regs_t *regs, int reg, int other_reg) +_jit_regs_set_value2(jit_gencode_t gen, _jit_regs_t *regs, int reg, int other_reg) { - regs->descs[2].reg = reg; - regs->descs[2].other_reg = other_reg; + if(reg >= 0 && !IS_STACK_REG(reg)) + { + set_regdesc_register(gen, regs, 2, reg, other_reg); + } } void -_jit_regs_add_scratch(_jit_regs_t *regs, int reg) +_jit_regs_add_scratch(jit_gencode_t gen, _jit_regs_t *regs, int reg) { if(regs->num_scratch < _JIT_REGS_SCRATCH_MAX) { - regs->scratch[regs->num_scratch++].reg = reg; + if(reg < 0) + { + ++regs->num_scratch; + } + else if(!IS_STACK_REG(reg)) + { + set_scratch_register(gen, regs, regs->num_scratch++, reg); + } } } void -_jit_regs_set_clobber(_jit_regs_t *regs, int reg) +_jit_regs_set_clobber(jit_gencode_t gen, _jit_regs_t *regs, int reg) { - jit_reg_set_used(regs->clobber, reg); + if(reg >= 0) + { + jit_reg_set_used(regs->clobber, reg); + } } void @@ -3905,84 +4138,25 @@ _jit_regs_scratch(_jit_regs_t *regs, int index) int _jit_regs_assign(jit_gencode_t gen, _jit_regs_t *regs) { - int index, out_index; + int reg, index, out_index; #ifdef JIT_REG_DEBUG printf("_jit_regs_assign()\n"); #endif - /* Set clobber flags. */ - if(regs->clobber_all) - { - for(index = 0; index < JIT_NUM_REGS; index++) - { - if((_jit_reg_info[index].flags & JIT_REG_FIXED) - || jit_reg_is_used(gen->permanent, index)) - { - continue; - } - jit_reg_set_used(regs->clobber, index); - } - } - - /* Spill all clobbered registers. */ - regs->spill = regs->clobber; - /* Process pre-assigned registers. */ - if(regs->descs[0].reg >= 0) - { - if(IS_STACK_REG(regs->descs[0].reg)) - { - return 0; - } - set_regdesc_register(gen, regs, 0, - regs->descs[0].reg, - regs->descs[0].other_reg); - } - if(regs->descs[1].reg >= 0) - { - if(IS_STACK_REG(regs->descs[1].reg)) - { - return 0; - } - set_regdesc_register(gen, regs, 1, - regs->descs[1].reg, - regs->descs[1].other_reg); - } - if(regs->descs[2].reg >= 0) - { - if(IS_STACK_REG(regs->descs[2].reg)) - { - return 0; - } - set_regdesc_register(gen, regs, 2, - regs->descs[2].reg, - regs->descs[2].other_reg); - } - - for(index = 0; index < regs->num_scratch; index++) - { - if(regs->scratch[index].reg >= 0) - { - if(IS_STACK_REG(regs->scratch[index].reg)) - { - return 0; - } - set_register_flags(gen, regs, regs->scratch[index].reg, 1, 0); - } - } for(index = 0; index < regs->num_scratch; index++) { if(regs->scratch[index].reg < 0 && regs->scratch[index].regset != jit_regused_init_used) { - regs->scratch[index].reg = use_cheapest_register( - gen, regs, -1, regs->scratch[index].regset); - if(regs->scratch[index].reg < 0) + reg = use_cheapest_register(gen, regs, -1, regs->scratch[index].regset); + if(reg < 0) { return 0; } + set_scratch_register(gen, regs, index, reg); } } @@ -4006,40 +4180,11 @@ _jit_regs_assign(jit_gencode_t gen, _jit_regs_t *regs) check_duplicate_value(regs, ®s->descs[0], ®s->descs[1]); check_duplicate_value(regs, ®s->descs[0], ®s->descs[2]); } - else if(regs->descs[0].value && regs->descs[out_index].value) + else if(!regs->free_dest && regs->descs[0].reg >= 0 && regs->descs[out_index].value) { - if(regs->descs[0].reg < 0 && regs->descs[out_index].reg < 0) - { - if(regs->descs[out_index].value->in_register - && gen->contents[regs->descs[out_index].value->reg].num_values == 1 - && !(/*regs->descs[out_index].live ||*/regs->descs[out_index].used)) - { - /* NOTE: The last condition makes sense for local register - allocation, review it for future global allocator. */ - use_cheapest_register( - gen, regs, out_index, regs->descs[out_index].regset); - if(regs->descs[out_index].reg < 0) - { - return 0; - } - } - else if(regs->descs[0].value->has_global_register - || (regs->descs[0].value->in_register - && gen->contents[regs->descs[0].value->reg].num_values == 1)) - { - use_cheapest_register(gen, regs, 0, regs->descs[0].regset); - if(regs->descs[0].reg < 0) - { - return 0; - } - } - } - if(regs->descs[0].reg >= 0) - { - set_regdesc_register(gen, regs, out_index, - regs->descs[0].reg, - regs->descs[0].other_reg); - } + set_regdesc_register(gen, regs, out_index, + regs->descs[0].reg, + regs->descs[0].other_reg); } if(regs->descs[1].value && regs->descs[1].reg < 0) { @@ -4060,7 +4205,7 @@ _jit_regs_assign(jit_gencode_t gen, _jit_regs_t *regs) } if(regs->descs[0].value && regs->descs[0].reg < 0) { - if(regs->descs[out_index].reg < 0) + if(regs->free_dest || regs->descs[out_index].reg < 0) { use_cheapest_register(gen, regs, 0, regs->descs[0].regset); if(regs->descs[0].reg < 0) @@ -4080,25 +4225,25 @@ _jit_regs_assign(jit_gencode_t gen, _jit_regs_t *regs) { if(regs->scratch[index].reg < 0) { - regs->scratch[index].reg = use_cheapest_register( - gen, regs, -1, jit_regused_init_used); - if(regs->scratch[index].reg < 0) + reg = use_cheapest_register(gen, regs, -1, jit_regused_init_used); + if(reg < 0) { return 0; } + set_scratch_register(gen, regs, index, reg); } } /* Collect information about registers. */ - if(!collect_register_info(gen, regs, 0)) + if(!set_regdesc_flags(gen, regs, 0)) { return 0; } - if(!collect_register_info(gen, regs, 1)) + if(!set_regdesc_flags(gen, regs, 1)) { return 0; } - if(!collect_register_info(gen, regs, 2)) + if(!set_regdesc_flags(gen, regs, 2)) { return 0; } @@ -4130,7 +4275,7 @@ _jit_regs_gen(jit_gencode_t gen, _jit_regs_t *regs) stack_start = reg; } - if(!jit_reg_is_used(regs->spill, reg)) + if(!jit_reg_is_used(regs->clobber, reg)) { continue; } @@ -4143,7 +4288,7 @@ _jit_regs_gen(jit_gencode_t gen, _jit_regs_t *regs) if(regs->branch) { /* After the branch is taken there is no way - to load global register back. */ + to load the global register back. */ return 0; } _jit_gen_spill_global(gen, reg, 0); @@ -4157,7 +4302,7 @@ _jit_regs_gen(jit_gencode_t gen, _jit_regs_t *regs) if(IS_STACK_REG(reg)) { top = get_stack_top(gen, stack_start); - while(top > reg && jit_reg_is_used(regs->spill, top)) + while(top > reg && jit_reg_is_used(regs->clobber, top)) { spill_reg(gen, regs, top); /* If one of the input values is on the top @@ -4311,7 +4456,7 @@ _jit_regs_commit(jit_gencode_t gen, _jit_regs_t *regs) /* Load clobbered global registers. */ for(reg = JIT_NUM_REGS - 1; reg >= 0; reg--) { - if(jit_reg_is_used(regs->spill, reg) && jit_reg_is_used(gen->permanent, reg)) + if(jit_reg_is_used(regs->clobber, reg) && jit_reg_is_used(gen->permanent, reg)) { _jit_gen_load_global(gen, reg, 0); } diff --git a/jit/jit-reg-alloc.h b/jit/jit-reg-alloc.h index ffb9460..15dd2b4 100644 --- a/jit/jit-reg-alloc.h +++ b/jit/jit-reg-alloc.h @@ -116,6 +116,7 @@ typedef struct unsigned clobber : 1; unsigned early_clobber : 1; unsigned duplicate : 1; + unsigned thrash : 1; unsigned save : 1; unsigned load : 1; unsigned copy : 1; @@ -158,7 +159,6 @@ typedef struct jit_regused_t assigned; jit_regused_t clobber; - jit_regused_t spill; int stack_start; int current_stack_top; @@ -166,16 +166,16 @@ typedef struct int loaded_stack_count; } _jit_regs_t; -void _jit_regs_init(_jit_regs_t *regs, int flags); +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); void _jit_regs_init_value2(_jit_regs_t *regs, jit_insn_t insn, int flags); -void _jit_regs_set_dest(_jit_regs_t *regs, int reg, int other_reg); -void _jit_regs_set_value1(_jit_regs_t *regs, int reg, int other_reg); -void _jit_regs_set_value2(_jit_regs_t *regs, int reg, int other_reg); -void _jit_regs_add_scratch(_jit_regs_t *regs, int reg); -void _jit_regs_set_clobber(_jit_regs_t *regs, int reg); +void _jit_regs_set_dest(jit_gencode_t gen, _jit_regs_t *regs, int reg, int other_reg); +void _jit_regs_set_value1(jit_gencode_t gen, _jit_regs_t *regs, int reg, int other_reg); +void _jit_regs_set_value2(jit_gencode_t gen, _jit_regs_t *regs, int reg, int other_reg); +void _jit_regs_add_scratch(jit_gencode_t gen, _jit_regs_t *regs, int reg); +void _jit_regs_set_clobber(jit_gencode_t gen, _jit_regs_t *regs, int reg); void _jit_regs_set_dest_from(_jit_regs_t *regs, jit_regused_t regset); void _jit_regs_set_value1_from(_jit_regs_t *regs, jit_regused_t regset); @@ -187,6 +187,7 @@ int _jit_regs_gen(jit_gencode_t gen, _jit_regs_t *regs); int _jit_regs_select(_jit_regs_t *regs); void _jit_regs_commit(jit_gencode_t gen, _jit_regs_t *regs); void _jit_regs_abort(jit_gencode_t gen, _jit_regs_t *regs); + unsigned char *_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); void _jit_regs_end(jit_gencode_t gen, _jit_regs_t *regs, unsigned char *inst); diff --git a/jit/jit-rules-x86.ins b/jit/jit-rules-x86.ins index b94095f..ca5b58d 100644 --- a/jit/jit-rules-x86.ins +++ b/jit/jit-rules-x86.ins @@ -431,457 +431,78 @@ JIT_OP_IMUL: binary x86_imul_reg_reg(inst, $1, $2); } -/* Spill before division to ensure that the arguments end up in - EAX and ECX, and that EDX is free */ -JIT_OP_IDIV: binary, spill_before, more_space - [reg, imm] -> { - switch($2) - { - case 0: - { - inst = throw_builtin(inst, func, JIT_RESULT_DIVISION_BY_ZERO); - } - break; - - case 1: break; - - case -1: - { - /* Dividing by -1 gives an exception if the argument - is minint, or simply negates for other values */ - unsigned char *patch; - x86_alu_reg_imm(inst, X86_CMP, $1, jit_min_int); - patch = inst; - x86_branch8(inst, X86_CC_NE, 0, 0); - inst = throw_builtin(inst, func, JIT_RESULT_ARITHMETIC); - x86_patch(patch, inst); - x86_neg_reg(inst, $1); - } - break; - - case 2: - { - x86_shift_reg_imm(inst, X86_SAR, $1, 1); - } - break; - - case 4: - { - x86_shift_reg_imm(inst, X86_SAR, $1, 2); - } - break; - - case 8: - { - x86_shift_reg_imm(inst, X86_SAR, $1, 3); - } - break; - - case 16: - { - x86_shift_reg_imm(inst, X86_SAR, $1, 4); - } - break; - - case 32: - { - x86_shift_reg_imm(inst, X86_SAR, $1, 5); - } - break; - - case 64: - { - x86_shift_reg_imm(inst, X86_SAR, $1, 6); - } - break; - - case 128: - { - x86_shift_reg_imm(inst, X86_SAR, $1, 7); - } - break; - - case 256: - { - x86_shift_reg_imm(inst, X86_SAR, $1, 8); - } - break; - - case 512: - { - x86_shift_reg_imm(inst, X86_SAR, $1, 9); - } - break; - - case 1024: - { - x86_shift_reg_imm(inst, X86_SAR, $1, 10); - } - break; - - case 2048: - { - x86_shift_reg_imm(inst, X86_SAR, $1, 11); - } - break; - - case 4096: - { - x86_shift_reg_imm(inst, X86_SAR, $1, 12); - } - break; - - case 8192: - { - x86_shift_reg_imm(inst, X86_SAR, $1, 13); - } - break; - - case 16384: - { - x86_shift_reg_imm(inst, X86_SAR, $1, 14); - } - break; - - case 32768: - { - x86_shift_reg_imm(inst, X86_SAR, $1, 15); - } - break; - - case 65536: - { - x86_shift_reg_imm(inst, X86_SAR, $1, 16); - } - break; - - case 0x00020000: - { - x86_shift_reg_imm(inst, X86_SAR, $1, 17); - } - break; - - case 0x00040000: - { - x86_shift_reg_imm(inst, X86_SAR, $1, 18); - } - break; - - case 0x00080000: - { - x86_shift_reg_imm(inst, X86_SAR, $1, 19); - } - break; - - case 0x00100000: - { - x86_shift_reg_imm(inst, X86_SAR, $1, 20); - } - break; - - case 0x00200000: - { - x86_shift_reg_imm(inst, X86_SAR, $1, 21); - } - break; - - case 0x00400000: - { - x86_shift_reg_imm(inst, X86_SAR, $1, 22); - } - break; - - case 0x00800000: - { - x86_shift_reg_imm(inst, X86_SAR, $1, 23); - } - break; - - case 0x01000000: - { - x86_shift_reg_imm(inst, X86_SAR, $1, 24); - } - break; - - case 0x02000000: - { - x86_shift_reg_imm(inst, X86_SAR, $1, 25); - } - break; - - case 0x04000000: - { - x86_shift_reg_imm(inst, X86_SAR, $1, 26); - } - break; - - case 0x08000000: - { - x86_shift_reg_imm(inst, X86_SAR, $1, 27); - } - break; - - case 0x10000000: - { - x86_shift_reg_imm(inst, X86_SAR, $1, 28); - } - break; - - case 0x20000000: - { - x86_shift_reg_imm(inst, X86_SAR, $1, 29); - } - break; - - case 0x40000000: - { - x86_shift_reg_imm(inst, X86_SAR, $1, 30); - } - break; - - case (jit_nint)0x80000000: - { - x86_shift_reg_imm(inst, X86_SAR, $1, 31); - } - break; - - default: - { - x86_mov_reg_imm(inst, X86_ECX, $2); - x86_cdq(inst); - x86_div_reg(inst, X86_ECX, 1); - } - break; - } - } - [reg, reg] -> { - unsigned char *patch, *patch2; - x86_alu_reg_reg(inst, X86_OR, $2, $2); - patch = inst; - x86_branch8(inst, X86_CC_NE, 0, 0); +JIT_OP_IDIV: more_space + [any, immzero] -> { inst = throw_builtin(inst, func, JIT_RESULT_DIVISION_BY_ZERO); - x86_patch(patch, inst); - x86_alu_reg_imm(inst, X86_CMP, $2, -1); - patch = inst; - x86_branch8(inst, X86_CC_NE, 0, 0); + } + [reg, imm, if("$2 == 1")] -> { + } + [reg, imm, if("$2 == -1")] -> { + /* Dividing by -1 gives an exception if the argument + is minint, or simply negates for other values */ + unsigned char *patch; x86_alu_reg_imm(inst, X86_CMP, $1, jit_min_int); - patch2 = inst; + patch = inst; x86_branch8(inst, X86_CC_NE, 0, 0); inst = throw_builtin(inst, func, JIT_RESULT_ARITHMETIC); x86_patch(patch, inst); - x86_patch(patch2, inst); - x86_cdq(inst); - x86_div_reg(inst, $2, 1); - } - -JIT_OP_IDIV_UN: binary, spill_before, more_space - [reg, imm] -> { - switch($2) - { - case 0: - { - inst = throw_builtin(inst, func, JIT_RESULT_DIVISION_BY_ZERO); - } - break; - - case 1: break; - - case 2: - { - x86_shift_reg_imm(inst, X86_SHR, $1, 1); - } - break; - - case 4: - { - x86_shift_reg_imm(inst, X86_SHR, $1, 2); - } - break; - - case 8: - { - x86_shift_reg_imm(inst, X86_SHR, $1, 3); - } - break; - - case 16: - { - x86_shift_reg_imm(inst, X86_SHR, $1, 4); - } - break; - - case 32: - { - x86_shift_reg_imm(inst, X86_SHR, $1, 5); - } - break; - - case 64: - { - x86_shift_reg_imm(inst, X86_SHR, $1, 6); - } - break; - - case 128: - { - x86_shift_reg_imm(inst, X86_SHR, $1, 7); - } - break; - - case 256: - { - x86_shift_reg_imm(inst, X86_SHR, $1, 8); - } - break; - - case 512: - { - x86_shift_reg_imm(inst, X86_SHR, $1, 9); - } - break; - - case 1024: - { - x86_shift_reg_imm(inst, X86_SHR, $1, 10); - } - break; - - case 2048: - { - x86_shift_reg_imm(inst, X86_SHR, $1, 11); - } - break; - - case 4096: - { - x86_shift_reg_imm(inst, X86_SHR, $1, 12); - } - break; - - case 8192: - { - x86_shift_reg_imm(inst, X86_SHR, $1, 13); - } - break; - - case 16384: - { - x86_shift_reg_imm(inst, X86_SHR, $1, 14); - } - break; - - case 32768: - { - x86_shift_reg_imm(inst, X86_SHR, $1, 15); - } - break; - - case 65536: - { - x86_shift_reg_imm(inst, X86_SHR, $1, 16); - } - break; - - case 0x00020000: - { - x86_shift_reg_imm(inst, X86_SHR, $1, 17); - } - break; - - case 0x00040000: - { - x86_shift_reg_imm(inst, X86_SHR, $1, 18); - } - break; - - case 0x00080000: - { - x86_shift_reg_imm(inst, X86_SHR, $1, 19); - } - break; - - case 0x00100000: - { - x86_shift_reg_imm(inst, X86_SHR, $1, 20); - } - break; - - case 0x00200000: - { - x86_shift_reg_imm(inst, X86_SHR, $1, 21); - } - break; - - case 0x00400000: - { - x86_shift_reg_imm(inst, X86_SHR, $1, 22); - } - break; - - case 0x00800000: - { - x86_shift_reg_imm(inst, X86_SHR, $1, 23); - } - break; - - case 0x01000000: - { - x86_shift_reg_imm(inst, X86_SHR, $1, 24); - } - break; - - case 0x02000000: - { - x86_shift_reg_imm(inst, X86_SHR, $1, 25); - } - break; - - case 0x04000000: - { - x86_shift_reg_imm(inst, X86_SHR, $1, 26); - } - break; - - case 0x08000000: - { - x86_shift_reg_imm(inst, X86_SHR, $1, 27); - } - break; - - case 0x10000000: - { - x86_shift_reg_imm(inst, X86_SHR, $1, 28); - } - break; - - case 0x20000000: - { - x86_shift_reg_imm(inst, X86_SHR, $1, 29); - } - break; - - case 0x40000000: - { - x86_shift_reg_imm(inst, X86_SHR, $1, 30); - } - break; - - case (jit_nint)0x80000000: - { - x86_shift_reg_imm(inst, X86_SHR, $1, 31); - } - break; + x86_neg_reg(inst, $1); + } + [reg, imm, if("(((jit_nuint)$2) & (((jit_nuint)$2) - 1)) == 0")] -> { + /* x & (x - 1) is equal to zero if x is a power of 2 */ + jit_nuint shift, value; + for(shift = 0, value = $2; value; value >>= 1) + { + ++shift; + } + x86_shift_reg_imm(inst, X86_SAR, $1, shift); + } + [reg("eax"), imm, scratch("?", "edx")] -> { + x86_mov_reg_imm(inst, $3, $2); + x86_cdq(inst); + x86_div_reg(inst, $3, 1); + } + [reg("eax"), reg, scratch("edx")] -> { + unsigned char *patch, *patch2; + x86_alu_reg_reg(inst, X86_OR, $2, $2); + patch = inst; + x86_branch8(inst, X86_CC_NE, 0, 0); + inst = throw_builtin(inst, func, JIT_RESULT_DIVISION_BY_ZERO); + x86_patch(patch, inst); + x86_alu_reg_imm(inst, X86_CMP, $2, -1); + patch = inst; + x86_branch8(inst, X86_CC_NE, 0, 0); + x86_alu_reg_imm(inst, X86_CMP, $1, jit_min_int); + patch2 = inst; + x86_branch8(inst, X86_CC_NE, 0, 0); + inst = throw_builtin(inst, func, JIT_RESULT_ARITHMETIC); + x86_patch(patch, inst); + x86_patch(patch2, inst); + x86_cdq(inst); + x86_div_reg(inst, $2, 1); + } - default: - { - x86_mov_reg_imm(inst, X86_ECX, $2); - x86_clear_reg(inst, X86_EDX); - x86_div_reg(inst, X86_ECX, 0); - } - break; +JIT_OP_IDIV_UN: more_space + [any, immzero] -> { + inst = throw_builtin(inst, func, JIT_RESULT_DIVISION_BY_ZERO); + } + [reg, imm, if("$2 == 1")] -> { + } + [reg, imm, if("(((jit_nuint)$2) & (((jit_nuint)$2) - 1)) == 0")] -> { + /* x & (x - 1) is equal to zero if x is a power of 2 */ + jit_nuint shift, value; + for(shift = 0, value = $2; value; value >>= 1) + { + ++shift; } + x86_shift_reg_imm(inst, X86_SAR, $1, shift); } - [reg, reg] -> { + [reg("eax"), imm, scratch("?", "edx")] -> { + x86_mov_reg_imm(inst, $3, $2); + x86_clear_reg(inst, X86_EDX); + x86_div_reg(inst, $3, 0); + } + [reg("eax"), reg, scratch("edx")] -> { unsigned char *patch; x86_alu_reg_reg(inst, X86_OR, $2, $2); patch = inst; @@ -892,48 +513,30 @@ JIT_OP_IDIV_UN: binary, spill_before, more_space x86_div_reg(inst, $2, 0); } -JIT_OP_IREM: binary, spill_before, more_space - [reg, imm] -> { - switch($2) - { - case 0: - { - inst = throw_builtin(inst, func, JIT_RESULT_DIVISION_BY_ZERO); - } - break; - - case 1: - { - x86_clear_reg(inst, $1); - } - break; - - case -1: - { - /* Dividing by -1 gives an exception if the argument - is minint, or simply gives a remainder of zero */ - unsigned char *patch; - x86_alu_reg_imm(inst, X86_CMP, $1, jit_min_int); - patch = inst; - x86_branch8(inst, X86_CC_NE, 0, 0); - inst = throw_builtin(inst, func, JIT_RESULT_ARITHMETIC); - x86_patch(patch, inst); - x86_clear_reg(inst, $1); - } - break; - - default: - { - x86_mov_reg_imm(inst, X86_ECX, $2); - x86_cdq(inst); - x86_div_reg(inst, X86_ECX, 1); - /* TODO: rearrange register assignments to avoid the move */ - x86_mov_reg_reg(inst, X86_EAX, X86_EDX, 4); - } - break; - } +JIT_OP_IREM: more_space + [any, immzero] -> { + inst = throw_builtin(inst, func, JIT_RESULT_DIVISION_BY_ZERO); } - [reg, reg] -> { + [reg, imm, if("$2 == 1")] -> { + x86_clear_reg(inst, $1); + } + [reg, imm, if("$2 == -1")] -> { + /* Dividing by -1 gives an exception if the argument + is minint, or simply gives a remainder of zero */ + unsigned char *patch; + x86_alu_reg_imm(inst, X86_CMP, $1, jit_min_int); + patch = inst; + x86_branch8(inst, X86_CC_NE, 0, 0); + inst = throw_builtin(inst, func, JIT_RESULT_ARITHMETIC); + x86_patch(patch, inst); + x86_clear_reg(inst, $1); + } + [=reg("edx"), *reg("eax"), imm, scratch("?")] -> { + x86_mov_reg_imm(inst, $3, $2); + x86_cdq(inst); + x86_div_reg(inst, $3, 1); + } + [=reg("edx"), *reg("eax"), reg] -> { unsigned char *patch, *patch2; x86_alu_reg_reg(inst, X86_OR, $2, $2); patch = inst; @@ -951,72 +554,25 @@ JIT_OP_IREM: binary, spill_before, more_space x86_patch(patch2, inst); x86_cdq(inst); x86_div_reg(inst, $2, 1); - x86_mov_reg_reg(inst, X86_EAX, X86_EDX, 4); } -JIT_OP_IREM_UN: binary, spill_before, more_space - [reg, imm] -> { - switch($2) - { - case 0: - { - inst = throw_builtin(inst, func, JIT_RESULT_DIVISION_BY_ZERO); - } - break; - - case 1: - { - x86_clear_reg(inst, $1); - } - break; - - case 2: - case 4: - case 8: - case 16: - case 32: - case 64: - case 128: - case 256: - case 512: - case 1024: - case 2048: - case 4096: - case 8192: - case 16384: - case 32768: - case 65536: - case 0x00020000: - case 0x00040000: - case 0x00080000: - case 0x00100000: - case 0x00200000: - case 0x00400000: - case 0x00800000: - case 0x01000000: - case 0x02000000: - case 0x04000000: - case 0x08000000: - case 0x10000000: - case 0x20000000: - case 0x40000000: - case (jit_nint)0x80000000: - { - x86_alu_reg_imm(inst, X86_AND, $1, $2 - 1); - } - break; - - default: - { - x86_mov_reg_imm(inst, X86_ECX, $2); - x86_clear_reg(inst, X86_EDX); - x86_div_reg(inst, X86_ECX, 0); - x86_mov_reg_reg(inst, X86_EAX, X86_EDX, 4); - } - break; - } +JIT_OP_IREM_UN: more_space + [any, immzero] -> { + inst = throw_builtin(inst, func, JIT_RESULT_DIVISION_BY_ZERO); } - [reg, reg] -> { + [reg, imm, if("$2 == 1")] -> { + x86_clear_reg(inst, $1); + } + [reg, imm, if("(((jit_nuint)$2) & (((jit_nuint)$2) - 1)) == 0")] -> { + /* x & (x - 1) is equal to zero if x is a power of 2 */ + x86_alu_reg_imm(inst, X86_AND, $1, $2 - 1); + } + [=reg("edx"), *reg("eax"), imm, scratch("?")] -> { + x86_mov_reg_imm(inst, $3, $2); + x86_clear_reg(inst, X86_EDX); + x86_div_reg(inst, $3, 0); + } + [=reg("edx"), *reg("eax"), reg] -> { unsigned char *patch; x86_alu_reg_reg(inst, X86_OR, $2, $2); patch = inst; @@ -1025,7 +581,6 @@ JIT_OP_IREM_UN: binary, spill_before, more_space x86_patch(patch, inst); x86_clear_reg(inst, X86_EDX); x86_div_reg(inst, $2, 0); - x86_mov_reg_reg(inst, X86_EAX, X86_EDX, 4); } JIT_OP_INEG: unary @@ -1916,35 +1471,19 @@ JIT_OP_CALL_FILTER_RETURN: manual TODO(); } -JIT_OP_ADDRESS_OF_LABEL: manual - [] -> { - unsigned char *inst; - jit_block_t block; - int reg; - - reg = _jit_regs_dest_value(gen, insn->dest); - - inst = gen->posn.ptr; - if(!jit_cache_check_for_n(&(gen->posn), 32)) - { - jit_cache_mark_full(&(gen->posn)); - return; - } - reg = _jit_reg_info[reg].cpu_reg; - +JIT_OP_ADDRESS_OF_LABEL: + [=reg] -> { block = jit_block_from_label(func, (jit_label_t)(insn->value1)); if(block->address) { - x86_mov_reg_imm(inst, reg, block->address); + x86_mov_reg_imm(inst, $0, block->address); } else { /* Output a placeholder and record on the block's fixup list */ - x86_mov_reg_imm(inst, reg, (int)(block->fixup_absolute_list)); + x86_mov_reg_imm(inst, $0, (int)(block->fixup_absolute_list)); block->fixup_absolute_list = (void *)(inst - 4); } - - gen->posn.ptr = inst; } /* @@ -2289,68 +1828,22 @@ JIT_OP_LOAD_RELATIVE_LONG: manual gen->posn.ptr = inst; } -JIT_OP_LOAD_RELATIVE_FLOAT32: manual - [] -> { - unsigned char *inst; - int reg = _jit_regs_load_value - (gen, insn->value1, 0, - (insn->flags & (JIT_INSN_VALUE1_NEXT_USE | - JIT_INSN_VALUE1_LIVE))); - _jit_regs_new_top(gen, insn->dest, 8); - inst = gen->posn.ptr; - if(!jit_cache_check_for_n(&(gen->posn), 32)) - { - jit_cache_mark_full(&(gen->posn)); - return; - } - reg = _jit_reg_info[reg].cpu_reg; - x86_fld_membase(inst, reg, insn->value2->address, 0); - gen->posn.ptr = inst; +JIT_OP_LOAD_RELATIVE_FLOAT32: + [=freg, reg, imm] -> { + x86_fld_membase(inst, $1, $2, 0); } -JIT_OP_LOAD_RELATIVE_FLOAT64: manual - [] -> { - unsigned char *inst; - int reg = _jit_regs_load_value - (gen, insn->value1, 0, - (insn->flags & (JIT_INSN_VALUE1_NEXT_USE | - JIT_INSN_VALUE1_LIVE))); - _jit_regs_new_top(gen, insn->dest, 8); - inst = gen->posn.ptr; - if(!jit_cache_check_for_n(&(gen->posn), 32)) - { - jit_cache_mark_full(&(gen->posn)); - return; - } - reg = _jit_reg_info[reg].cpu_reg; - x86_fld_membase(inst, reg, insn->value2->address, 1); - gen->posn.ptr = inst; +JIT_OP_LOAD_RELATIVE_FLOAT64: + [=freg, reg, imm] -> { + x86_fld_membase(inst, $1, $2, 1); } - -JIT_OP_LOAD_RELATIVE_NFLOAT: manual - [] -> { - unsigned char *inst; - int reg = _jit_regs_load_value - (gen, insn->value1, 0, - (insn->flags & (JIT_INSN_VALUE1_NEXT_USE | - JIT_INSN_VALUE1_LIVE))); - _jit_regs_new_top(gen, insn->dest, 8); - inst = gen->posn.ptr; - if(!jit_cache_check_for_n(&(gen->posn), 32)) - { - jit_cache_mark_full(&(gen->posn)); - return; - } - reg = _jit_reg_info[reg].cpu_reg; - if(sizeof(jit_nfloat) != sizeof(jit_float64)) - { - x86_fld80_membase(inst, reg, insn->value2->address); - } - else - { - x86_fld_membase(inst, reg, insn->value2->address, 1); - } - gen->posn.ptr = inst; + +JIT_OP_LOAD_RELATIVE_NFLOAT: + [=freg, reg, imm, if("sizeof(jit_nfloat) != sizeof(jit_float64)")] -> { + x86_fld80_membase(inst, $1, $2); + } + [=freg, reg, imm, if("sizeof(jit_nfloat) == sizeof(jit_float64)")] -> { + x86_fld_membase(inst, $1, $2, 1); } JIT_OP_LOAD_RELATIVE_STRUCT: unary_branch, more_space @@ -2547,94 +2040,25 @@ JIT_OP_LOAD_ELEMENT_LONG: manual gen->posn.ptr = inst; } -JIT_OP_LOAD_ELEMENT_FLOAT32: manual - [] -> { - unsigned char *inst; - int reg, reg2; - - reg = _jit_regs_load_value(gen, insn->value1, 0, - (insn->flags & (JIT_INSN_VALUE1_NEXT_USE | JIT_INSN_VALUE1_LIVE))); - reg2 = _jit_regs_load_value(gen, insn->value2, 0, - (insn->flags & (JIT_INSN_VALUE2_NEXT_USE | JIT_INSN_VALUE2_LIVE))); - _jit_regs_new_top(gen, insn->dest, 8); - - inst = gen->posn.ptr; - if(!jit_cache_check_for_n(&(gen->posn), 32)) - { - jit_cache_mark_full(&(gen->posn)); - return; - } - - reg = _jit_reg_info[reg].cpu_reg; - reg2 = _jit_reg_info[reg2].cpu_reg; - - x86_fld_memindex(inst, reg, 0, reg2, 2, 0); - - gen->posn.ptr = inst; +JIT_OP_LOAD_ELEMENT_FLOAT32: + [=freg, reg, reg] -> { + x86_fld_memindex(inst, $1, 0, $2, 2, 0); } -JIT_OP_LOAD_ELEMENT_FLOAT64: manual - [] -> { - unsigned char *inst; - int reg, reg2, reg3; - - reg = _jit_regs_load_value(gen, insn->value1, 0, - (insn->flags & (JIT_INSN_VALUE1_NEXT_USE | JIT_INSN_VALUE1_LIVE))); - reg2 = _jit_regs_load_value(gen, insn->value2, 0, - (insn->flags & (JIT_INSN_VALUE2_NEXT_USE | JIT_INSN_VALUE2_LIVE))); - reg3 = _jit_regs_new_top(gen, insn->dest, 8); - - inst = gen->posn.ptr; - if(!jit_cache_check_for_n(&(gen->posn), 32)) - { - jit_cache_mark_full(&(gen->posn)); - return; - } - - reg = _jit_reg_info[reg].cpu_reg; - reg2 = _jit_reg_info[reg2].cpu_reg; - - x86_fld_memindex(inst, reg, 0, reg2, 3, 1); - - gen->posn.ptr = inst; +JIT_OP_LOAD_ELEMENT_FLOAT64: + [=freg, reg, reg] -> { + x86_fld_memindex(inst, $1, 0, $2, 3, 1); } -JIT_OP_LOAD_ELEMENT_NFLOAT: manual - [] -> { - unsigned char *inst; - int reg, reg2, reg3; - - reg = _jit_regs_load_value - (gen, insn->value1, 0, - (insn->flags & (JIT_INSN_VALUE1_NEXT_USE | JIT_INSN_VALUE1_LIVE))); - reg2 = _jit_regs_load_value - (gen, insn->value2, sizeof(jit_nfloat) != sizeof(jit_float64), - (insn->flags & (JIT_INSN_VALUE2_NEXT_USE | JIT_INSN_VALUE2_LIVE))); - reg3 = _jit_regs_new_top(gen, insn->dest, 8); - - inst = gen->posn.ptr; - if(!jit_cache_check_for_n(&(gen->posn), 32)) - { - jit_cache_mark_full(&(gen->posn)); - return; - } - - reg = _jit_reg_info[reg].cpu_reg; - reg2 = _jit_reg_info[reg2].cpu_reg; - - if(sizeof(jit_nfloat) != sizeof(jit_float64)) - { - /* lea reg2, [reg2 + reg2 * 2] */ - x86_lea_memindex(inst, reg2, reg2, 0, reg2, 1); - /* fld [reg2 * 4] */ - x86_fld80_memindex(inst, reg, 0, reg2, 2); - } - else - { - x86_fld_memindex(inst, reg, 0, reg2, 3, 1); - } - - gen->posn.ptr = inst; +JIT_OP_LOAD_ELEMENT_NFLOAT: + [=freg, reg, +reg, if("sizeof(jit_nfloat) != sizeof(jit_float64)")] -> { + /* lea $2, [$2 + $2 * 2] */ + x86_lea_memindex(inst, $2, $2, 0, $2, 1); + /* fld [$2 * 4] */ + x86_fld80_memindex(inst, $1, 0, $2, 2); + } + [=freg, reg, reg, if("sizeof(jit_nfloat) == sizeof(jit_float64)")] -> { + x86_fld_memindex(inst, $1, 0, $2, 3, 1); } JIT_OP_STORE_ELEMENT_BYTE: ternary diff --git a/tools/gen-rules-parser.y b/tools/gen-rules-parser.y index c280b03..9495ba5 100644 --- a/tools/gen-rules-parser.y +++ b/tools/gen-rules-parser.y @@ -822,8 +822,10 @@ gensel_output_code( char *code, char *names[MAX_PATTERN], char *other_names[MAX_PATTERN], + int free_dest, int in_line) { + char first; int index; /* Output the clause code */ @@ -833,15 +835,16 @@ gensel_output_code( } while(*code != '\0') { - if(*code == '$' && code[1] >= '1' && code[1] <= '9') + first = free_dest ? '0' : '1'; + if(*code == '$' && code[1] >= first && code[1] <= (first + MAX_PATTERN)) { - index = code[1] - '1'; + index = code[1] - first; printf(names[index]); code += 2; } - else if(*code == '%' && code[1] >= '1' && code[1] <= '9') + else if(*code == '%' && code[1] >= first && code[1] <= (first + MAX_PATTERN)) { - index = code[1] - '1'; + index = code[1] - first; printf(other_names[index]); code += 2; } @@ -870,14 +873,15 @@ static void gensel_output_clause_code( gensel_clause_t clause, char *names[MAX_PATTERN], - char *other_names[MAX_PATTERN]) + char *other_names[MAX_PATTERN], + int free_dest) { /* Output the line number information from the original file */ #if 0 printf("#line %ld \"%s\"\n", clause->linenum, clause->filename); #endif - gensel_output_code(clause->pattern, clause->code, names, other_names, 0); + gensel_output_code(clause->pattern, clause->code, names, other_names, free_dest, 0); } /* @@ -905,7 +909,7 @@ static void gensel_output_clauses(gensel_clause_t clauses, gensel_option_t optio printf("\t_jit_regs_spill_all(gen);\n"); } gensel_init_names(MAX_PATTERN, names, other_names); - gensel_output_clause_code(clauses, names, other_names); + gensel_output_clause_code(clauses, names, other_names, 0); return; } @@ -1087,7 +1091,7 @@ static void gensel_output_clauses(gensel_clause_t clauses, gensel_option_t optio gensel_output_code( clause->pattern, pattern->values->value, - names, other_names, 1); + names, other_names, free_dest, 1); printf(")"); seen_option = 1; break; @@ -1137,7 +1141,7 @@ static void gensel_output_clauses(gensel_clause_t clauses, gensel_option_t optio if(contains_registers) { seen_option = 0; - printf("\t\t_jit_regs_init(®s, "); + printf("\t\t_jit_regs_init(gen, ®s, "); if(clobber_all) { seen_option = 1; @@ -1275,7 +1279,7 @@ static void gensel_output_clauses(gensel_clause_t clauses, gensel_option_t optio { if(pattern->values->type == GENSEL_VALUE_STRING) { - printf("\t\t_jit_regs_set_%s(®s, _jit_regs_lookup(\"%s\"), -1);\n", + printf("\t\t_jit_regs_set_%s(gen, ®s, _jit_regs_lookup(\"%s\"), -1);\n", args[index], pattern->values->value); } else @@ -1308,12 +1312,12 @@ static void gensel_output_clauses(gensel_clause_t clauses, gensel_option_t optio { if(pattern->values->next && pattern->values->next->value) { - printf("\t\t_jit_regs_set_%s(®s, _jit_regs_lookup(\"%s\"), _jit_regs_lookup(\"%s\"));\n", + printf("\t\t_jit_regs_set_%s(gen, ®s, _jit_regs_lookup(\"%s\"), _jit_regs_lookup(\"%s\"));\n", args[index], pattern->values->value, pattern->values->next->value); } else { - printf("\t\t_jit_regs_set_%s(®s, _jit_regs_lookup(\"%s\"), -1);\n", + printf("\t\t_jit_regs_set_%s(gen, ®s, _jit_regs_lookup(\"%s\"), -1);\n", args[index], pattern->values->value); } } @@ -1358,7 +1362,7 @@ static void gensel_output_clauses(gensel_clause_t clauses, gensel_option_t optio { if(values->type == GENSEL_VALUE_STRING) { - printf("\t\t_jit_regs_add_scratch(®s, _jit_regs_lookup(\"%s\"));\n", + printf("\t\t_jit_regs_add_scratch(gen, ®s, _jit_regs_lookup(\"%s\"));\n", values->value); } else @@ -1379,7 +1383,7 @@ static void gensel_output_clauses(gensel_clause_t clauses, gensel_option_t optio } else { - printf("\t\t_jit_regs_add_scratch(®s, -1);\n"); + printf("\t\t_jit_regs_add_scratch(gen, ®s, -1);\n"); } ++regs; ++index; @@ -1393,7 +1397,7 @@ static void gensel_output_clauses(gensel_clause_t clauses, gensel_option_t optio { if(values->value && strcmp(values->value, "*") != 0) { - printf("\t\t_jit_regs_set_clobber(®s, _jit_regs_lookup(\"%s\"));\n", + printf("\t\t_jit_regs_set_clobber(gen, ®s, _jit_regs_lookup(\"%s\"));\n", values->value); } values = values->next; @@ -1441,7 +1445,7 @@ static void gensel_output_clauses(gensel_clause_t clauses, gensel_option_t optio gensel_output_code( clause->pattern, space->values->value, - names, other_names, 1); + names, other_names, free_dest, 1); printf(")"); } else @@ -1538,7 +1542,7 @@ static void gensel_output_clauses(gensel_clause_t clauses, gensel_option_t optio } gensel_build_var_index(clause->pattern, names, other_names); - gensel_output_clause_code(clause, names, other_names); + gensel_output_clause_code(clause, names, other_names, free_dest); /* Copy "inst" back into the generation context */ if(gensel_new_inst_type)