From 941f10cb638d55252f489265918bceb5e4464f9e Mon Sep 17 00:00:00 2001 From: Aleksey Demakov Date: Fri, 29 Dec 2006 23:16:15 +0000 Subject: [PATCH] add support for register classes, clean up rule syntax and reg alloc interface --- ChangeLog | 14 + jit/jit-reg-alloc.c | 699 ++++++++++++++++-------------- jit/jit-reg-alloc.h | 74 ++-- jit/jit-rules-alpha.ins | 98 +++-- jit/jit-rules-x86.ins | 233 +++++----- tools/gen-rules-parser.y | 875 ++++++++++++++++---------------------- tools/gen-rules-scanner.l | 25 +- 7 files changed, 976 insertions(+), 1042 deletions(-) diff --git a/ChangeLog b/ChangeLog index 9baa196..f528eba 100644 --- a/ChangeLog +++ b/ChangeLog @@ -6,6 +6,20 @@ * jit/jit-rules-x86.c (_jit_init_backend): initialize x86 register classes. + * jit/jit-reg-alloc.h, jit/jit-reg-alloc.c: specify register class + for each value and scratch register. Clean up interface. + + * tools/gen-rules-scanner.l, tools/gen-rules-parser.y: add register + class declaration; "reg", "lreg", "freg" are not keywords anymore. + "scratch" requires register class specification. "clobber" accepts + register class which means all registers in the class are clobbered. + Remove "only", "spill_before", "unary", and "binary" keywords. + Replace "unary_note" and "binary_note" with "note". Also replace + "unary_branch" and "binary_branch" with "branch". + + * jit/jit-rules-alpha.ins, jit/jit-rules-x86.ins: update according + to the new rule syntax. + 2006-12-20 Aleksey Demakov * jit/jit-thread.h, jit/jit-thread.c: add _jit_global_lock mutex. diff --git a/jit/jit-reg-alloc.c b/jit/jit-reg-alloc.c index 355d1e0..d6ca615 100644 --- a/jit/jit-reg-alloc.c +++ b/jit/jit-reg-alloc.c @@ -62,11 +62,11 @@ mostly don't have to worry about it: #define COST_COPY 4 #define COST_SPILL_DIRTY 16 -#define COST_SPILL_DIRTY_GLOBAL 2 +#define COST_SPILL_DIRTY_GLOBAL 4 #define COST_SPILL_CLEAN 1 #define COST_SPILL_CLEAN_GLOBAL 1 -#define COST_GLOBAL_BIAS 1 -#define COST_THRASH 32 +#define COST_GLOBAL_BIAS 2 +#define COST_THRASH 100 #define COST_CLOBBER_GLOBAL 1000 #ifdef JIT_BACKEND_X86 @@ -398,10 +398,16 @@ clobbers_register(jit_gencode_t gen, _jit_regs_t *regs, int index, int reg, int if(regs->ternary || !regs->descs[0].value) { /* this is either a ternary or binary or unary note */ - if(IS_STACK_REG(reg) || regs->descs[index].clobber) + if(regs->descs[index].clobber) { flags = CLOBBER_INPUT_VALUE; } +#ifdef JIT_REG_STACK + else if(IS_STACK_REG(reg) && !regs->no_pop) + { + flags = CLOBBER_INPUT_VALUE; + } +#endif else { flags = CLOBBER_NONE; @@ -439,12 +445,14 @@ clobbers_register(jit_gencode_t gen, _jit_regs_t *regs, int index, int reg, int { flags = CLOBBER_NONE; } - else if(regs->on_stack && !regs->no_pop) +#ifdef JIT_REG_STACK + else if(IS_STACK_REG(reg) && !regs->no_pop) { /* this is a binary or unary stack op -- the input value is either popped or overwritten by the output */ flags = CLOBBER_INPUT_VALUE; } +#endif else if(reg == regs->descs[0].reg || reg == regs->descs[0].other_reg || other_reg == regs->descs[0].reg) @@ -503,37 +511,18 @@ set_scratch_register(jit_gencode_t gen, _jit_regs_t *regs, int index, int reg) } } -/* - * Initialize value descriptor. - */ -static void -init_regdesc(_jit_regs_t *regs, int index) -{ - _jit_regdesc_t *desc; - - desc = ®s->descs[index]; - desc->value = 0; - desc->reg = -1; - desc->other_reg = -1; - desc->stack_reg = -1; - desc->regset = jit_regused_init_used; - desc->live = 0; - desc->used = 0; - desc->clobber = 0; - desc->early_clobber = 0; - desc->duplicate = 0; - desc->thrash = 0; - desc->save = 0; - desc->load = 0; - desc->copy = 0; - desc->kill = 0; -} - /* * Set value information. */ static void -set_regdesc_value(_jit_regs_t *regs, int index, jit_value_t value, int flags, int live, int used) +set_regdesc_value( + _jit_regs_t *regs, + int index, + jit_value_t value, + int flags, + _jit_regclass_t *regclass, + int live, + int used) { _jit_regdesc_t *desc; @@ -551,6 +540,7 @@ set_regdesc_value(_jit_regs_t *regs, int index, jit_value_t value, int flags, in desc->clobber = 1; } } + desc->regclass = regclass; desc->live = live; desc->used = used; } @@ -595,6 +585,7 @@ set_regdesc_flags(jit_gencode_t gen, _jit_regs_t *regs, int index) _jit_regdesc_t *desc; int reg, other_reg; int clobber, clobber_input; + int is_input, is_live_input, is_used_input; #ifdef JIT_REG_DEBUG printf("set_regdesc_flags(index = %d)\n", index); @@ -606,125 +597,138 @@ set_regdesc_flags(jit_gencode_t gen, _jit_regs_t *regs, int index) return 1; } - /* Find the register the value is already in (if any). */ - if(desc->value->in_register) + /* See if the value clobbers the register it is assigned to. */ + clobber = clobbers_register(gen, regs, index, desc->reg, desc->other_reg); + + /* See if this is an input value and whether it is alive. */ + if(regs->ternary) { - reg = desc->value->reg; - if(gen->contents[reg].is_long_start) + is_input = 1; + is_live_input = desc->live; + is_used_input = desc->used; + } + else if(index > 0) + { + is_input = 1; + if(regs->descs[0].value == desc->value) { - other_reg = OTHER_REG(reg); + is_live_input = is_used_input = 0; } else { - other_reg = -1; + is_live_input = desc->live; + is_used_input = desc->used; } } else { - reg = -1; - other_reg = -1; + is_input = is_live_input = is_used_input = 0; } - /* See if the value clobbers the register it is assigned to. */ - clobber = clobbers_register(gen, regs, index, desc->reg, desc->other_reg); - if((clobber & CLOBBER_INPUT_VALUE) != 0) + if(is_input) { - clobber_input = 1; - } - else if(jit_reg_is_used(regs->clobber, desc->reg)) - { - clobber_input = 1; - } - else if(desc->other_reg >= 0 && jit_reg_is_used(regs->clobber, desc->other_reg)) - { - clobber_input = 1; - } - else - { - clobber_input = 0; - } - if((clobber & CLOBBER_REG) != 0) - { - jit_reg_set_used(regs->clobber, desc->reg); - } - if((clobber & CLOBBER_OTHER_REG) != 0) - { - jit_reg_set_used(regs->clobber, desc->other_reg); - } - - /* See if the input value is thrashed by other inputs or clobbered - by the output. The allocator tries to avoid thrashing so it may - only take place if the register is assigned explicitly. For x87 - registers the problem of thrashing may be best solved with fxch - but as the stack registers are never assigned explicitely there - is no such problem for them at all. */ - if(reg >= 0 && (index > 0 || regs->ternary)) - { - if(index != 0 && regs->ternary && !are_values_equal(desc, ®s->descs[0])) + /* Find the register the value is already in (if any). */ + if(desc->value->in_register) { - 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))) + reg = desc->value->reg; + if(gen->contents[reg].is_long_start) { - desc->thrash = 1; - } - } - 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; + other_reg = OTHER_REG(reg); } - } - 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))) + else { - desc->thrash = 1; + other_reg = -1; } } - - if(desc->thrash) + else { 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) + /* See if the input value is thrashed by other inputs. 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) { - if(desc->value->global_reg != desc->reg - && !(reg >= 0 && reg == desc->reg)) + if(index != 0 && regs->ternary + && !are_values_equal(desc, ®s->descs[0])) { - desc->copy = 1; + if(reg == regs->descs[0].reg + || reg == regs->descs[0].other_reg + || (other_reg >= 0 + && (other_reg == regs->descs[0].reg + || other_reg == regs->descs[0].other_reg))) + { + desc->thrash = 1; + } + } + if(index != 1 && !are_values_equal(desc, ®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->store = 1; } } - else + + /* See if the value needs to be loaded or copied or none. */ + if(reg != desc->reg) { - if(reg < 0) + if(desc->value->has_global_register) + { + desc->copy = (desc->value->global_reg != desc->reg); + } + else if(reg < 0) { desc->load = 1; } - else if(reg != desc->reg) + else { desc->copy = 1; } } + /* See if the input value is destroyed by the instruction. */ + if(desc->copy) + { + clobber_input = 0; + } + else if(jit_reg_is_used(regs->clobber, desc->reg) + || (desc->other_reg >= 0 + && jit_reg_is_used(regs->clobber, desc->other_reg))) + { + clobber_input = 1; + } + else + { + clobber_input = ((clobber & CLOBBER_INPUT_VALUE) != 0); + } + /* See if the input value needs to be saved before the instruction and if it stays or not in the register after the instruction. */ @@ -732,32 +736,28 @@ set_regdesc_flags(jit_gencode_t gen, _jit_regs_t *regs, int index) { desc->kill = 1; } - else if(reg >= 0) + else if(clobber_input) { - if(desc->used) - { - if(!desc->copy && clobber_input) - { - desc->save = 1; - desc->kill = 1; - } - } - else - { - if(desc->live) - { - desc->save = 1; - } - desc->kill = 1; - } + desc->store = (is_live_input || is_used_input); + desc->kill = 1; + } + else if(!is_used_input) + { + desc->store = is_live_input; + desc->kill = 1; } - else if(desc->load) + +#ifdef JIT_REG_STACK + /* Count stack registers. */ + if(IS_STACK_REG(desc->reg)) { - if(!desc->used || clobber_input) + ++(regs->wanted_stack_count); + if(!desc->load && !desc->copy) { - desc->kill = 1; + ++(regs->loaded_stack_count); } } +#endif } /* See if the value clobbers a global register. In this case the global @@ -771,16 +771,14 @@ set_regdesc_flags(jit_gencode_t gen, _jit_regs_t *regs, int index) desc->kill = 1; } - if(IS_STACK_REG(desc->reg)) + /* Set clobber flags (this indicates registers to be spilled). */ + if((clobber & CLOBBER_REG) != 0) { - if(index > 0 || regs->ternary) - { - ++(regs->wanted_stack_count); - if(!(desc->load || desc->copy)) - { - ++(regs->loaded_stack_count); - } - } + jit_reg_set_used(regs->clobber, desc->reg); + } + if((clobber & CLOBBER_OTHER_REG) != 0) + { + jit_reg_set_used(regs->clobber, desc->other_reg); } #ifdef JIT_REG_DEBUG @@ -801,7 +799,7 @@ set_regdesc_flags(jit_gencode_t gen, _jit_regs_t *regs, int index) 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("store = %d\n", desc->store); printf("load = %d\n", desc->load); printf("copy = %d\n", desc->copy); printf("kill = %d\n", desc->kill); @@ -983,31 +981,25 @@ thrashes_value(jit_gencode_t gen, static int choose_scratch_register(jit_gencode_t gen, _jit_regs_t *regs, int index) { - int reg, type; + _jit_regclass_t *regclass; + int reg_index, reg; int use_cost; int suitable_reg; int suitable_cost; int suitable_age; - type = JIT_REG_WORD; + regclass = regs->scratch[index].regclass; suitable_reg = -1; suitable_cost = COST_TOO_MUCH; suitable_age = -1; - for(reg = 0; reg < JIT_NUM_REGS; reg++) + for(reg_index = 0; reg_index < regclass->num_regs; reg_index++) { - if((_jit_reg_info[reg].flags & type) == 0) - { - continue; - } + reg = regclass->regs[reg_index]; if(jit_reg_is_used(regs->assigned, reg)) { continue; } - if(!jit_reg_is_used(regs->scratch[index].regset, reg)) - { - continue; - } #if ALLOW_CLOBBER_GLOBAL if(jit_reg_is_used(gen->permanent, reg)) @@ -1067,38 +1059,28 @@ choose_scratch_register(jit_gencode_t gen, _jit_regs_t *regs, int index) static int choose_output_register(jit_gencode_t gen, _jit_regs_t *regs) { - int type, need_pair; - int reg, other_reg; + _jit_regclass_t *regclass; + int need_pair; + int reg_index, reg, other_reg; int use_cost; int suitable_reg, suitable_other_reg; int suitable_cost; int suitable_age; + regclass = regs->descs[0].regclass; need_pair = _jit_regs_needs_long_pair(regs->descs[0].value->type); - type = get_register_type(regs->descs[0].value, need_pair); - if(!type) - { - return 0; - } suitable_reg = -1; suitable_other_reg = -1; suitable_cost = COST_TOO_MUCH; suitable_age = -1; - for(reg = 0; reg < JIT_NUM_REGS; reg++) + for(reg_index = 0; reg_index < regclass->num_regs; reg_index++) { - if((_jit_reg_info[reg].flags & type) == 0) - { - continue; - } + reg = regclass->regs[reg_index]; if(jit_reg_is_used(gen->inhibit, reg)) { continue; } - if(!jit_reg_is_used(regs->descs[0].regset, reg)) - { - continue; - } if(need_pair) { @@ -1174,10 +1156,16 @@ choose_output_register(jit_gencode_t gen, _jit_regs_t *regs) && regs->descs[2].value->in_register && regs->descs[2].value->reg == reg) { - if(regs->commutative || regs->x87_arith) + if(regs->commutative) { use_cost = 0; } +#ifdef JIT_REG_STACK + else if(regs->x87_arith) + { + use_cost = 0; + } +#endif else { use_cost = COST_THRASH; @@ -1227,26 +1215,21 @@ static void choose_input_order(jit_gencode_t gen, _jit_regs_t *regs) { _jit_regdesc_t temp_desc; - int keep1, keep2; - - if(regs->ternary || regs->free_dest || !regs->descs[0].value) - { - regs->dest_input_index = 0; - return; - } if(regs->descs[2].value && regs->descs[2].value->in_register && regs->descs[2].value->reg == regs->descs[0].reg && regs->descs[2].value != regs->descs[1].value) { - if(regs->on_stack && regs->x87_arith) +#ifdef JIT_REG_STACK + if(regs->x87_arith) { regs->no_pop = 1; regs->reverse_dest = 1; regs->dest_input_index = 2; } else +#endif { if(regs->commutative) { @@ -1266,11 +1249,14 @@ choose_input_order(jit_gencode_t gen, _jit_regs_t *regs) regs->dest_input_index = 0; } +#ifdef JIT_REG_STACK /* Choose between pop and no-pop instructions. */ - if(regs->on_stack && regs->x87_arith && !regs->no_pop + if(!regs->no_pop && regs->x87_arith && !regs->clobber_all && !regs->clobber_stack && regs->descs[1].value && regs->descs[2].value) { + int keep1, keep2; + /* Determine if we might want to keep either of input values in registers after the instruction completion. */ if(regs->descs[1].value->in_register) @@ -1296,15 +1282,17 @@ choose_input_order(jit_gencode_t gen, _jit_regs_t *regs) regs->no_pop = (keep1 || keep2); } +#endif } static int choose_input_register(jit_gencode_t gen, _jit_regs_t *regs, int index) { + _jit_regclass_t *regclass; _jit_regdesc_t *desc; _jit_regdesc_t *desc2; - int type, need_pair; - int reg, other_reg; + int need_pair; + int reg_index, reg, other_reg; int use_cost; int suitable_reg, suitable_other_reg; int suitable_cost; @@ -1317,12 +1305,8 @@ choose_input_register(jit_gencode_t gen, _jit_regs_t *regs, int index) return 0; } + regclass = regs->descs[index].regclass; need_pair = _jit_regs_needs_long_pair(desc->value->type); - type = get_register_type(desc->value, need_pair); - if(!type) - { - return 0; - } if(index == regs->dest_input_index) { @@ -1337,20 +1321,13 @@ choose_input_register(jit_gencode_t gen, _jit_regs_t *regs, int index) suitable_other_reg = -1; suitable_cost = COST_TOO_MUCH; suitable_age = -1; - for(reg = 0; reg < JIT_NUM_REGS; reg++) + for(reg_index = 0; reg_index < regclass->num_regs; reg_index++) { - if((_jit_reg_info[reg].flags & type) == 0) - { - continue; - } + reg = regclass->regs[reg_index]; if(jit_reg_is_used(regs->assigned, reg)) { continue; } - if(!jit_reg_is_used(desc->regset, reg)) - { - continue; - } if(need_pair) { @@ -1463,9 +1440,10 @@ choose_input_register(jit_gencode_t gen, _jit_regs_t *regs, int index) static void check_duplicate_value(_jit_regs_t *regs, _jit_regdesc_t *desc1, _jit_regdesc_t *desc2) { - if((!regs->on_stack || regs->x87_arith) - && are_values_equal(desc1, desc2) - && desc1->reg >= 0 && desc2->reg < 0 + if(desc2->reg < 0 && desc1->reg >= 0 && are_values_equal(desc1, desc2) +#ifdef JIT_REG_STACK + && (!IS_STACK_REG(desc1->reg) || regs->x87_arith) +#endif && !desc1->early_clobber && !desc2->early_clobber) { desc2->reg = desc1->reg; @@ -1501,7 +1479,7 @@ adjust_assignment(jit_gencode_t gen, _jit_regs_t *regs, int index) index = regs->dest_input_index; } - if(regs->x87_arith && desc->value->in_register && !desc->copy) + if(desc->value->in_register && !desc->copy && regs->x87_arith) { desc->reg = desc->value->reg; } @@ -1523,7 +1501,8 @@ select_stack_order(jit_gencode_t gen, _jit_regs_t *regs) int top_index; /* Choose instruction that results into fewer exchanges. */ - if(regs->on_stack && regs->no_pop && (regs->commutative || regs->reversible)) + if(regs->wanted_stack_count > 1 && regs->no_pop + && (regs->commutative || regs->reversible)) { desc1 = ®s->descs[1]; desc2 = ®s->descs[2]; @@ -1806,7 +1785,7 @@ free_value(jit_gencode_t gen, jit_value_t value, int reg, int other_reg, int tem #ifdef JIT_REG_DEBUG printf("free_value(value = "); jit_dump_value(stdout, jit_value_get_function(value), value, 0); - printf(", reg = %d, other_reg = %d)\n", reg, other_reg); + printf(", reg = %d, other_reg = %d, temp = %d)\n", reg, other_reg, temp); #endif /* Never free global registers. */ @@ -1847,7 +1826,7 @@ save_value(jit_gencode_t gen, jit_value_t value, int reg, int other_reg, int fre #ifdef JIT_REG_DEBUG printf("save_value(value = "); jit_dump_value(stdout, jit_value_get_function(value), value, 0); - printf(", reg = %d, other_reg = %d)\n", reg, other_reg); + printf(", reg = %d, other_reg = %d, free=%d)\n", reg, other_reg, free); #endif /* First take care of values that reside in global registers. */ if(value->has_global_register) @@ -2066,7 +2045,7 @@ save_input_value(jit_gencode_t gen, _jit_regs_t *regs, int index) #endif desc = ®s->descs[index]; - if(!(desc->value && desc->value->in_register && desc->save)) + if(!desc->value || !desc->value->in_register || !desc->store) { return; } @@ -2291,13 +2270,16 @@ abort_input_value(jit_gencode_t gen, _jit_regs_t *regs, int index) } static void -commit_input_value(jit_gencode_t gen, _jit_regs_t *regs, int index) +commit_input_value(jit_gencode_t gen, _jit_regs_t *regs, int index, int go_down_stack) { _jit_regdesc_t *desc; int reg, other_reg; +#ifdef JIT_REG_STACK + int is_down_stack = 0; +#endif #ifdef JIT_REG_DEBUG - printf("commit_input_value(%d)\n", index); + printf("commit_input_value(%d, %d)\n", index, go_down_stack); #endif desc = ®s->descs[index]; @@ -2309,19 +2291,34 @@ commit_input_value(jit_gencode_t gen, _jit_regs_t *regs, int index) if(desc->copy) { #ifdef JIT_REG_STACK - if(IS_STACK_REG(desc->reg) && !regs->copy) + if(IS_STACK_REG(desc->reg)) { - --(gen->reg_stack_top); + if(!go_down_stack) + { + if(1/*!regs->copy*/) + { + --(gen->reg_stack_top); + } + gen->contents[desc->reg].used_for_temp = 0; + } + is_down_stack = 1; } + else #endif - gen->contents[desc->reg].used_for_temp = 0; - if(desc->other_reg >= 0) { - gen->contents[desc->other_reg].used_for_temp = 0; + gen->contents[desc->reg].used_for_temp = 0; + if(desc->other_reg >= 0) + { + gen->contents[desc->other_reg].used_for_temp = 0; + } } } +#ifdef JIT_REG_STACK + if(desc->kill && desc->value->in_register && is_down_stack == go_down_stack) +#else if(desc->kill && desc->value->in_register) +#endif { reg = desc->value->reg; if(gen->contents[reg].is_long_start) @@ -2332,12 +2329,21 @@ commit_input_value(jit_gencode_t gen, _jit_regs_t *regs, int index) { other_reg = -1; } - unbind_value(gen, desc->value, reg, other_reg); #ifdef JIT_REG_STACK - if(IS_STACK_REG(reg) && !regs->copy) + if(is_down_stack) { - --(gen->reg_stack_top); + free_value(gen, desc->value, reg, other_reg, 0); } + else + { + unbind_value(gen, desc->value, reg, other_reg); + if(IS_STACK_REG(reg) /*&& !regs->copy*/) + { + --(gen->reg_stack_top); + } + } +#else + unbind_value(gen, desc->value, reg, other_reg); #endif } @@ -2369,7 +2375,7 @@ commit_output_value(jit_gencode_t gen, _jit_regs_t *regs) } #ifdef JIT_REG_STACK - if(IS_STACK_REG(desc->reg) && !regs->copy) + if(IS_STACK_REG(desc->reg) /*&& !regs->copy*/) { ++(gen->reg_stack_top); } @@ -2951,90 +2957,79 @@ _jit_regs_init(jit_gencode_t gen, _jit_regs_t *regs, int flags) { int index; - regs->clobber_all = (flags & _JIT_REGS_CLOBBER_ALL) != 0; - regs->clobber_stack = (flags & _JIT_REGS_CLOBBER_STACK) != 0; + jit_memset(regs, 0, sizeof(_jit_regs_t)); + regs->ternary = (flags & _JIT_REGS_TERNARY) != 0; regs->branch = (flags & _JIT_REGS_BRANCH) != 0; regs->copy = (flags & _JIT_REGS_COPY) != 0; regs->commutative = (flags & _JIT_REGS_COMMUTATIVE) != 0; + regs->free_dest = (flags & _JIT_REGS_FREE_DEST) != 0; +#ifdef JIT_REG_STACK regs->on_stack = (flags & _JIT_REGS_STACK) != 0; regs->x87_arith = (flags & _JIT_REGS_X87_ARITH) != 0; regs->reversible = (flags & _JIT_REGS_REVERSIBLE) != 0; - regs->free_dest = (flags & _JIT_REGS_FREE_DEST) != 0; - - regs->no_pop = 0; - regs->reverse_dest = 0; - regs->reverse_args = 0; + regs->no_pop = (regs->on_stack & regs->copy) != 0; +#endif for(index = 0; index < _JIT_REGS_VALUE_MAX; index++) { - init_regdesc(regs, index); + regs->descs[index].reg = -1; + regs->descs[index].other_reg = -1; + regs->descs[index].stack_reg = -1; } for(index = 0; index < _JIT_REGS_SCRATCH_MAX; index++) { regs->scratch[index].reg = -1; - regs->scratch[index].regset = jit_regused_init_used; } - regs->num_scratch = 0; - regs->dest_input_index = 0; - /* Set clobber flags. */ regs->clobber = jit_regused_init; - if(regs->clobber_all || regs->clobber_stack) - { - 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; - } - if(regs->clobber_all || IS_STACK_REG(index)) - { - jit_reg_set_used(regs->clobber, index); - } - } - } - regs->assigned = gen->inhibit; - - regs->wanted_stack_count = 0; - regs->loaded_stack_count = 0; } void -_jit_regs_init_dest(_jit_regs_t *regs, jit_insn_t insn, int flags) +_jit_regs_init_dest(_jit_regs_t *regs, jit_insn_t insn, int flags, _jit_regclass_t *regclass) { if((insn->flags & JIT_INSN_DEST_OTHER_FLAGS) == 0) { - set_regdesc_value(regs, 0, insn->dest, flags, + set_regdesc_value(regs, 0, insn->dest, flags, regclass, (insn->flags & JIT_INSN_DEST_LIVE) != 0, (insn->flags & JIT_INSN_DEST_NEXT_USE) != 0); } } void -_jit_regs_init_value1(_jit_regs_t *regs, jit_insn_t insn, int flags) +_jit_regs_init_value1(_jit_regs_t *regs, jit_insn_t insn, int flags, _jit_regclass_t *regclass) { if((insn->flags & JIT_INSN_VALUE1_OTHER_FLAGS) == 0) { - set_regdesc_value(regs, 1, insn->value1, flags, + set_regdesc_value(regs, 1, insn->value1, flags, regclass, (insn->flags & JIT_INSN_VALUE1_LIVE) != 0, (insn->flags & JIT_INSN_VALUE1_NEXT_USE) != 0); } } void -_jit_regs_init_value2(_jit_regs_t *regs, jit_insn_t insn, int flags) +_jit_regs_init_value2(_jit_regs_t *regs, jit_insn_t insn, int flags, _jit_regclass_t *regclass) { if((insn->flags & JIT_INSN_VALUE2_OTHER_FLAGS) == 0) { - set_regdesc_value(regs, 2, insn->value2, flags, + set_regdesc_value(regs, 2, insn->value2, flags, regclass, (insn->flags & JIT_INSN_VALUE2_LIVE) != 0, (insn->flags & JIT_INSN_VALUE2_NEXT_USE) != 0); } } +void +_jit_regs_add_scratch(_jit_regs_t *regs, _jit_regclass_t *regclass) +{ + if(regs->num_scratch < _JIT_REGS_SCRATCH_MAX) + { + regs->scratch[regs->num_scratch].reg = -1; + regs->scratch[regs->num_scratch].regclass = regclass; + ++regs->num_scratch; + } +} + void _jit_regs_set_dest(jit_gencode_t gen, _jit_regs_t *regs, int reg, int other_reg) { @@ -3063,95 +3058,52 @@ _jit_regs_set_value2(jit_gencode_t gen, _jit_regs_t *regs, int reg, int other_re } void -_jit_regs_add_scratch(jit_gencode_t gen, _jit_regs_t *regs, int reg) -{ - if(regs->num_scratch < _JIT_REGS_SCRATCH_MAX) - { - 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_gencode_t gen, _jit_regs_t *regs, int reg) -{ - if(reg >= 0) - { - jit_reg_set_used(regs->clobber, reg); - } -} - -void -_jit_regs_set_dest_from(_jit_regs_t *regs, jit_regused_t regset) -{ - regs->descs[0].regset = regset; -} - -void -_jit_regs_set_value1_from(_jit_regs_t *regs, jit_regused_t regset) +_jit_regs_set_scratch(jit_gencode_t gen, _jit_regs_t *regs, int index, int reg) { - regs->descs[1].regset = regset; -} - -void -_jit_regs_set_value2_from(_jit_regs_t *regs, jit_regused_t regset) -{ - regs->descs[2].regset = regset; -} - -void -_jit_regs_add_scratch_from(_jit_regs_t *regs, jit_regused_t regset) -{ - if(regs->num_scratch < _JIT_REGS_SCRATCH_MAX) + if(index < regs->num_scratch && index >= 0 && reg >= 0 && !IS_STACK_REG(reg)) { - regs->scratch[regs->num_scratch++].regset = regset; + set_scratch_register(gen, regs, index, reg); } } int -_jit_regs_dest(_jit_regs_t *regs) +_jit_regs_get_dest(_jit_regs_t *regs) { return regs->descs[0].reg; } int -_jit_regs_value1(_jit_regs_t *regs) +_jit_regs_get_value1(_jit_regs_t *regs) { return regs->descs[1].reg; } int -_jit_regs_value2(_jit_regs_t *regs) +_jit_regs_get_value2(_jit_regs_t *regs) { return regs->descs[2].reg; } int -_jit_regs_dest_other(_jit_regs_t *regs) +_jit_regs_get_dest_other(_jit_regs_t *regs) { return regs->descs[0].other_reg; } int -_jit_regs_value1_other(_jit_regs_t *regs) +_jit_regs_get_value1_other(_jit_regs_t *regs) { return regs->descs[1].other_reg; } int -_jit_regs_value2_other(_jit_regs_t *regs) +_jit_regs_get_value2_other(_jit_regs_t *regs) { return regs->descs[2].other_reg; } int -_jit_regs_scratch(_jit_regs_t *regs, int index) +_jit_regs_get_scratch(_jit_regs_t *regs, int index) { if(index < regs->num_scratch && index >= 0) { @@ -3160,6 +3112,58 @@ _jit_regs_scratch(_jit_regs_t *regs, int index) return -1; } +void +_jit_regs_clobber(_jit_regs_t *regs, int reg) +{ + if(reg >= 0) + { + jit_reg_set_used(regs->clobber, reg); + } +} + +void +_jit_regs_clobber_class(jit_gencode_t gen, _jit_regs_t *regs, _jit_regclass_t *regclass) +{ + int index; + +#ifdef JIT_REG_STACK + if((regclass->flags & JIT_REG_IN_STACK) != 0) + { + regs->clobber_stack = 1; + } +#endif + + for(index = 0; index < regclass->num_regs; index++) + { + if(jit_reg_is_used(gen->permanent, index)) + { + continue; + } + jit_reg_set_used(regs->clobber, regclass->regs[index]); + } +} + +void +_jit_regs_clobber_all(jit_gencode_t gen, _jit_regs_t *regs) +{ + int index; + + regs->clobber_all = 1; + + for(index = 0; index < JIT_NUM_REGS; index++) + { + if((_jit_reg_info[index].flags & JIT_REG_FIXED) != 0) + { + continue; + } + if(jit_reg_is_used(gen->permanent, index)) + { + continue; + } + jit_reg_set_used(regs->clobber, index); + } +} + int _jit_regs_assign(jit_gencode_t gen, _jit_regs_t *regs) { @@ -3172,8 +3176,9 @@ _jit_regs_assign(jit_gencode_t gen, _jit_regs_t *regs) /* For binary or unary ops with explicitely assigned registers the output always goes to the same register as the first input value unless this is a three-address instruction. */ - if(!(regs->ternary || regs->free_dest) - && regs->descs[0].value && regs->descs[1].value) + if(!regs->ternary && !regs->free_dest + && regs->descs[0].value + && regs->descs[1].value) { if(regs->descs[0].reg >= 0) { @@ -3412,6 +3417,7 @@ _jit_regs_gen(jit_gencode_t gen, _jit_regs_t *regs) return 1; } +#ifdef JIT_REG_STACK int _jit_regs_select(_jit_regs_t *regs) { @@ -3433,6 +3439,7 @@ _jit_regs_select(_jit_regs_t *regs) return flags; } +#endif void _jit_regs_commit(jit_gencode_t gen, _jit_regs_t *regs) @@ -3444,24 +3451,72 @@ _jit_regs_commit(jit_gencode_t gen, _jit_regs_t *regs) #endif #ifdef JIT_REG_STACK - if(regs->reverse_args) + if(regs->wanted_stack_count > 0) { - commit_input_value(gen, regs, 1); - commit_input_value(gen, regs, 2); + int reg1, reg2; + + /* The stack registers has to be freed from the top down. It is + assumed that only binary instructions may have more than one + stack register. The unary instruction may not do that for + obvious reasons. The practical observation is that no ternary + instruction in libjit does that as well. */ + if(regs->reverse_args) + { + commit_input_value(gen, regs, 1, 0); + commit_input_value(gen, regs, 2, 0); + } + else + { + commit_input_value(gen, regs, 2, 0); + commit_input_value(gen, regs, 1, 0); + } + if(regs->ternary) + { + commit_input_value(gen, regs, 0, 0); + } + else + { + commit_output_value(gen, regs); + } + + /* If the allocator makes a copy of a value that was already on + the stack we might need to free the original register as well. + In general, the allocator makes a copy if the value is going + to be destroyed by the instruction while it is still used + (according to the liveness analysis). But the original value + needs to be freed only if it is no longer used. So this extra + code seems useless. But there were cases when the allocator + miscalculated the cost of spilling and made a copy when it + was not needed. So this code serves as a precaution against + such problematic cases. */ + reg1 = ((regs->descs[1].value && regs->descs[1].value->in_register) + ? regs->descs[1].value->reg : -1); + reg2 = ((regs->descs[2].value && regs->descs[2].value->in_register) + ? regs->descs[2].value->reg : -1); + if(reg1 > reg2) + { + commit_input_value(gen, regs, 1, 1); + commit_input_value(gen, regs, 2, 1); + } + else + { + commit_input_value(gen, regs, 2, 1); + commit_input_value(gen, regs, 1, 1); + } } else #endif { - commit_input_value(gen, regs, 2); - commit_input_value(gen, regs, 1); - } - if(regs->ternary) - { - commit_input_value(gen, regs, 0); - } - else - { - commit_output_value(gen, regs); + commit_input_value(gen, regs, 2, 0); + commit_input_value(gen, regs, 1, 0); + if(regs->ternary) + { + commit_input_value(gen, regs, 0, 0); + } + else + { + commit_output_value(gen, regs); + } } /* Load clobbered global registers. */ diff --git a/jit/jit-reg-alloc.h b/jit/jit-reg-alloc.h index ed76751..e163b74 100644 --- a/jit/jit-reg-alloc.h +++ b/jit/jit-reg-alloc.h @@ -22,6 +22,7 @@ #define _JIT_REG_ALLOC_H #include "jit-rules.h" +#include "jit-reg-class.h" #ifdef __cplusplus extern "C" { @@ -40,16 +41,14 @@ extern "C" { /* * Flags for _jit_regs_init(). */ -#define _JIT_REGS_CLOBBER_ALL 0x0001 -#define _JIT_REGS_TERNARY 0x0002 -#define _JIT_REGS_BRANCH 0x0004 -#define _JIT_REGS_COPY 0x0008 -#define _JIT_REGS_STACK 0x0010 -#define _JIT_REGS_X87_ARITH 0x0020 -#define _JIT_REGS_COMMUTATIVE 0x0040 -#define _JIT_REGS_REVERSIBLE 0x0080 -#define _JIT_REGS_FREE_DEST 0x0100 -#define _JIT_REGS_CLOBBER_STACK 0x0200 +#define _JIT_REGS_TERNARY 0x0001 +#define _JIT_REGS_BRANCH 0x0002 +#define _JIT_REGS_COPY 0x0004 +#define _JIT_REGS_FREE_DEST 0x0008 +#define _JIT_REGS_COMMUTATIVE 0x0010 +#define _JIT_REGS_STACK 0x0020 +#define _JIT_REGS_X87_ARITH 0x0040 +#define _JIT_REGS_REVERSIBLE 0X0080 /* * Flags for _jit_regs_init_dest(), _jit_regs_init_value1(), and @@ -74,14 +73,14 @@ typedef struct int reg; int other_reg; int stack_reg; - jit_regused_t regset; + _jit_regclass_t *regclass; unsigned live : 1; unsigned used : 1; unsigned clobber : 1; unsigned early_clobber : 1; unsigned duplicate : 1; unsigned thrash : 1; - unsigned save : 1; + unsigned store : 1; unsigned load : 1; unsigned copy : 1; unsigned kill : 1; @@ -94,7 +93,7 @@ typedef struct typedef struct { int reg; - jit_regused_t regset; + _jit_regclass_t *regclass; } _jit_scratch_t; @@ -108,19 +107,23 @@ typedef struct int num_scratch; unsigned clobber_all : 1; - unsigned clobber_stack : 1; + unsigned ternary : 1; unsigned branch : 1; unsigned copy : 1; unsigned commutative : 1; + unsigned free_dest : 1; + +#ifdef JIT_REG_STACK unsigned on_stack : 1; unsigned x87_arith : 1; unsigned reversible : 1; - unsigned free_dest : 1; + unsigned clobber_stack : 1; unsigned no_pop : 1; unsigned reverse_dest : 1; unsigned reverse_args : 1; +#endif /* The input value index that is going to be overwritten by the destination value. For ordinary binary and unary @@ -132,8 +135,10 @@ typedef struct jit_regused_t assigned; jit_regused_t clobber; +#ifdef JIT_REG_STACK int wanted_stack_count; int loaded_stack_count; +#endif } _jit_regs_t; @@ -150,39 +155,44 @@ void _jit_regs_force_out(jit_gencode_t gen, jit_value_t value, int is_dest); int _jit_regs_load_value(jit_gencode_t gen, jit_value_t value, int destroy, int used_again); void _jit_regs_init(jit_gencode_t gen, _jit_regs_t *regs, int flags); -void _jit_regs_init_dest(_jit_regs_t *regs, jit_insn_t insn, int flags); -void _jit_regs_init_value1(_jit_regs_t *regs, jit_insn_t insn, int flags); -void _jit_regs_init_value2(_jit_regs_t *regs, jit_insn_t insn, int flags); + +void _jit_regs_init_dest(_jit_regs_t *regs, jit_insn_t insn, + int flags, _jit_regclass_t *regclass); +void _jit_regs_init_value1(_jit_regs_t *regs, jit_insn_t insn, + int flags, _jit_regclass_t *regclass); +void _jit_regs_init_value2(_jit_regs_t *regs, jit_insn_t insn, + int flags, _jit_regclass_t *regclass); +void _jit_regs_add_scratch(_jit_regs_t *regs, _jit_regclass_t *regclass); 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_scratch(jit_gencode_t gen, _jit_regs_t *regs, int index, 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); -void _jit_regs_set_value2_from(_jit_regs_t *regs, jit_regused_t regset); -void _jit_regs_add_scratch_from(_jit_regs_t *regs, jit_regused_t regset); +void _jit_regs_clobber(_jit_regs_t *regs, int reg); +void _jit_regs_clobber_class(jit_gencode_t gen, _jit_regs_t *regs, _jit_regclass_t *regclass); +void _jit_regs_clobber_all(jit_gencode_t gen, _jit_regs_t *regs); int _jit_regs_assign(jit_gencode_t gen, _jit_regs_t *regs); int _jit_regs_gen(jit_gencode_t gen, _jit_regs_t *regs); +#ifdef JIT_REG_STACK 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); +int _jit_regs_get_value2(_jit_regs_t *regs); +int _jit_regs_get_dest_other(_jit_regs_t *regs); +int _jit_regs_get_value1_other(_jit_regs_t *regs); +int _jit_regs_get_value2_other(_jit_regs_t *regs); +int _jit_regs_get_scratch(_jit_regs_t *regs, int index); + 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); -int _jit_regs_dest(_jit_regs_t *regs); -int _jit_regs_value1(_jit_regs_t *regs); -int _jit_regs_value2(_jit_regs_t *regs); -int _jit_regs_dest_other(_jit_regs_t *regs); -int _jit_regs_value1_other(_jit_regs_t *regs); -int _jit_regs_value2_other(_jit_regs_t *regs); -int _jit_regs_scratch(_jit_regs_t *regs, int index); - #ifdef __cplusplus }; #endif diff --git a/jit/jit-rules-alpha.ins b/jit/jit-rules-alpha.ins index fc7e911..ac6dfd4 100644 --- a/jit/jit-rules-alpha.ins +++ b/jit/jit-rules-alpha.ins @@ -20,29 +20,32 @@ %inst_type alpha_inst +%regclass reg alpha_reg +%regclass lreg alpha_reg + /* * Conversion opcodes. */ -JIT_OP_TRUNC_SBYTE: unary +JIT_OP_TRUNC_SBYTE: [reg] -> { alpha_slli(inst,$1,56,$1); alpha_srai(inst,$1,56,$1); } -JIT_OP_TRUNC_UBYTE: unary +JIT_OP_TRUNC_UBYTE: [reg] -> { _alpha_li8(inst,ALPHA_AT,0xff); alpha_and(inst,$1,ALPHA_AT,$1); } -JIT_OP_TRUNC_SHORT: unary +JIT_OP_TRUNC_SHORT: [reg] -> { alpha_slli(inst,$1,56,$1); alpha_srai(inst,$1,56,$1); } -JIT_OP_TRUNC_USHORT: unary +JIT_OP_TRUNC_USHORT: [reg] -> { alpha_slli(inst,$1,56,$1); alpha_srli(inst,$1,56,$1); @@ -69,7 +72,7 @@ JIT_OP_TRUNC_USHORT: unary */ /* return value1 + value2; */ -JIT_OP_IADD: binary +JIT_OP_IADD: [=reg, reg, imm, if("$3 == 0")] -> { alpha_mov(inst,$2,$1); } @@ -78,7 +81,7 @@ JIT_OP_IADD: binary } /* return value1 - value2; */ -JIT_OP_ISUB: binary +JIT_OP_ISUB: [=reg, reg, imm, if("$3 == 0")] -> { alpha_mov(inst,$2,$1); } @@ -88,7 +91,7 @@ JIT_OP_ISUB: binary /* return value1 * value2; */ /* TODO add more trivial IMUL imm rules */ -JIT_OP_IMUL: binary +JIT_OP_IMUL: [=reg, reg, imm, if("$3 == 1")] -> { alpha_mov(inst,$2,$1); } @@ -113,27 +116,27 @@ JIT_OP_IMUL: binary */ /* return -value1; */ -JIT_OP_INEG: unary +JIT_OP_INEG: [reg] -> { /* Alpha has no neg operation, do $1 = 0 - $1; instead */ alpha_subl(inst,ALPHA_ZERO,$1,$1); } /* return value1 + value2 */ -JIT_OP_LADD: binary +JIT_OP_LADD: [=lreg, lreg, lreg] -> { alpha_addq(inst,$3,$2,$1); } /* return value1 - value2 */ -JIT_OP_LSUB: binary +JIT_OP_LSUB: [=lreg, lreg, lreg] -> { alpha_subq(inst,$3,$2,$1); } /* return value1 * value2 */ /* TODO add more trivial LMUL imm rules */ -JIT_OP_LMUL: binary +JIT_OP_LMUL: [=lreg, lreg, imm, if("$3 == 1")] -> { alpha_mov(inst,$2,$1); } @@ -147,7 +150,7 @@ JIT_OP_LMUL: binary alpha_mulq(inst,$3,$2,$1); } -JIT_OP_LNEG: unary +JIT_OP_LNEG: [lreg] -> { /* Alpha has no neg operation, do $1 = 0 - $1; instead */ alpha_subq(inst,ALPHA_ZERO,$1,$1); @@ -167,22 +170,22 @@ JIT_OP_LNEG: unary /* * Bitwise opcodes. */ -JIT_OP_IAND: binary +JIT_OP_IAND: [=reg, reg, reg] -> { alpha_and(inst,$3,$2,$1); } -JIT_OP_IOR: binary +JIT_OP_IOR: [=reg, reg, reg] -> { alpha_or(inst,$3,$2,$1); } -JIT_OP_IXOR: binary +JIT_OP_IXOR: [=reg, reg, reg] -> { alpha_xor(inst,$3,$2,$1); } -JIT_OP_INOT: unary +JIT_OP_INOT: [reg] -> { _alpha_li32(inst,ALPHA_AT,0xffffffff); alpha_xor(inst,ALPHA_AT,$1,$1); @@ -196,38 +199,38 @@ JIT_OP_INOT: unary * these to work properly. */ -JIT_OP_LAND: binary +JIT_OP_LAND: [=reg, reg, reg] -> { alpha_and(inst,$3,$2,$1); } -JIT_OP_LOR: binary +JIT_OP_LOR: [=reg, reg, reg] -> { alpha_or(inst,$3,$2,$1); } -JIT_OP_LXOR: binary +JIT_OP_LXOR: [=reg, reg, reg] -> { alpha_xor(inst,$3,$2,$1); } -JIT_OP_LNOT: unary +JIT_OP_LNOT: [reg] -> { _alpha_li64(inst,ALPHA_AT,0xffffffff); alpha_xor(inst,ALPHA_AT,$1,$1); } -JIT_OP_LSHL: binary +JIT_OP_LSHL: [=reg, reg, reg] -> { alpha_sll(inst,$3,$2,$1); } -JIT_OP_LSHR: binary +JIT_OP_LSHR: [=reg, reg, reg] -> { alpha_srl(inst,$3,$2,$1); } -JIT_OP_LSHR_UN: binary +JIT_OP_LSHR_UN: [=reg, reg, reg] -> { alpha_sra(inst,$3,$2,$1); } @@ -236,25 +239,25 @@ JIT_OP_LSHR_UN: binary * Branch opcodes */ -JIT_OP_BR: spill_before +JIT_OP_BR: branch [] -> { /* branch if ALPHA_ZERO is zero (this is always true) */ alpha_output_branch(func, inst, ALPHA_OP_BEQ, insn, ALPHA_ZERO); } -JIT_OP_BR_IFALSE: unary_branch +JIT_OP_BR_IFALSE: branch [reg] -> { /* banch if $1 == 0 */ alpha_output_branch(func, inst, ALPHA_OP_BEQ, insn, $1); } -JIT_OP_BR_ITRUE: unary_branch +JIT_OP_BR_ITRUE: branch [reg] -> { /* branch if $1 != 0 */ alpha_output_branch(func, inst, ALPHA_OP_BNE, insn, $1); } -JIT_OP_BR_IEQ: binary_branch +JIT_OP_BR_IEQ: branch [reg, reg] -> { /* $1 == $2 -> $at */ alpha_cmpeq(inst, $1, $2, ALPHA_AT); @@ -263,7 +266,7 @@ JIT_OP_BR_IEQ: binary_branch alpha_output_branch(func, inst, ALPHA_OP_BEQ, insn, ALPHA_AT); } -JIT_OP_BR_INE: binary_branch +JIT_OP_BR_INE: branch [reg, reg] -> { /* $1 == $2 -> $at */ alpha_cmpeq(inst, $1, $2, ALPHA_AT); @@ -271,7 +274,8 @@ JIT_OP_BR_INE: binary_branch /* branch if $at == 0 */ alpha_output_branch(func, inst, ALPHA_OP_BNE, insn, ALPHA_AT); } -JIT_OP_BR_ILT: binary_branch + +JIT_OP_BR_ILT: branch [reg, reg] -> { /* $1 < $2 -> $at */ alpha_cmplt(inst, $1, $2, ALPHA_AT); @@ -280,7 +284,7 @@ JIT_OP_BR_ILT: binary_branch alpha_output_branch(func, inst, ALPHA_OP_BEQ, insn, ALPHA_AT); } -JIT_OP_BR_ILT_UN: binary_branch +JIT_OP_BR_ILT_UN: branch [reg, reg] -> { /* $1 < $2 -> $at */ alpha_cmpult(inst, $1, $2, ALPHA_AT); @@ -289,7 +293,7 @@ JIT_OP_BR_ILT_UN: binary_branch alpha_output_branch(func, inst, ALPHA_OP_BEQ, insn, ALPHA_AT); } -JIT_OP_BR_ILE: binary_branch +JIT_OP_BR_ILE: branch [reg, reg] -> { /* $1 <= $2 -> $at */ alpha_cmple(inst, $1, $2, ALPHA_AT); @@ -298,7 +302,7 @@ JIT_OP_BR_ILE: binary_branch alpha_output_branch(func, inst, ALPHA_OP_BEQ, insn, ALPHA_AT); } -JIT_OP_BR_ILE_UN: binary_branch +JIT_OP_BR_ILE_UN: branch [reg, reg] -> { /* $1 <= $2 -> $at */ alpha_cmpule(inst, $1, $2, ALPHA_AT); @@ -307,7 +311,7 @@ JIT_OP_BR_ILE_UN: binary_branch alpha_output_branch(func, inst, ALPHA_OP_BEQ, insn, ALPHA_AT); } -JIT_OP_BR_IGT: +JIT_OP_BR_IGT: branch [reg, reg] -> { /* $1 <= $2 -> $at */ alpha_cmpgt(inst, $1, $2, ALPHA_AT); @@ -316,7 +320,7 @@ JIT_OP_BR_IGT: alpha_output_branch(func, inst, ALPHA_OP_BEQ, insn, ALPHA_AT); } -JIT_OP_BR_IGT_UN: +JIT_OP_BR_IGT_UN: branch [reg, reg] -> { /* $1 > $2 -> $at */ alpha_cmpugt(inst, $1, $2, ALPHA_AT); @@ -325,7 +329,7 @@ JIT_OP_BR_IGT_UN: alpha_output_branch(func, inst, ALPHA_OP_BEQ, insn, ALPHA_AT); } -JIT_OP_BR_IGE: +JIT_OP_BR_IGE: branch [reg, reg] -> { /* $1 >= $2 -> $at */ alpha_cmpge(inst, $1, $2, ALPHA_AT); @@ -334,7 +338,7 @@ JIT_OP_BR_IGE: alpha_output_branch(func, inst, ALPHA_OP_BEQ, insn, ALPHA_AT); } -JIT_OP_BR_IGE_UN: +JIT_OP_BR_IGE_UN: branch [reg, reg] -> { /* $1 >= $2 -> $at */ alpha_cmpuge(inst, $1, $2, ALPHA_AT); @@ -348,34 +352,34 @@ JIT_OP_BR_IGE_UN: * Comparison opcodes. */ -JIT_OP_IEQ: binary +JIT_OP_IEQ: [=reg, reg, reg] -> { alpha_cmpeq(inst,$3,$2,$1); } -JIT_OP_INE: binary +JIT_OP_INE: [=reg, reg, reg] -> { alpha_cmpeq(inst,$3,$2,$1); alpha_cmpeq(inst,$1,ALPHA_ZERO,$1); } -JIT_OP_ILT: binary +JIT_OP_ILT: [=reg, reg, reg] -> { alpha_cmplt(inst,$3,$2,$1); } -JIT_OP_ILT_UN: binary +JIT_OP_ILT_UN: [=reg, reg, reg] -> { alpha_cmpult(inst,$3,$2,$1); } -JIT_OP_ILE: binary +JIT_OP_ILE: [=reg, reg, reg] -> { alpha_cmple(inst,$3,$2,$1); } -JIT_OP_ILE_UN: binary +JIT_OP_ILE_UN: [=reg, reg, reg] -> { alpha_cmpule(inst,$3,$2,$1); } @@ -396,7 +400,7 @@ JIT_OP_ILE_UN: binary * Pointer check opcodes. */ -/* TODO: JIT_OP_CHECK_NULL: unary_note */ +/* TODO: JIT_OP_CHECK_NULL: note */ /* * Function calls. @@ -415,13 +419,13 @@ JIT_OP_RETURN: jump_to_epilog(gen, inst, block); } -JIT_OP_RETURN_INT: unary_branch +JIT_OP_RETURN_INT: branch [reg] -> { alpha_mov(inst,$1,ALPHA_V0); jump_to_epilog(gen, inst, block); } -JIT_OP_RETURN_LONG: unary_branch +JIT_OP_RETURN_LONG: branch [reg] -> { alpha_mov(inst,$1,ALPHA_V0); jump_to_epilog(gen, inst, block); @@ -443,7 +447,7 @@ JIT_OP_RETURN_REG: manual /* Nothing to do here */; } -JIT_OP_PUSH_INT: unary_note +JIT_OP_PUSH_INT: note [imm] -> { alpha_li(inst,ALPHA_AT,$1); alpha_stq(inst,ALPHA_AT,ALPHA_SP,0); @@ -454,7 +458,7 @@ JIT_OP_PUSH_INT: unary_note alpha_lda(inst,ALPHA_SP,ALPHA_SP,-8); } -JIT_OP_PUSH_LONG: unary_note +JIT_OP_PUSH_LONG: note [imm] -> { alpha_li(inst,ALPHA_AT,$1); alpha_stq(inst,ALPHA_AT,ALPHA_SP,0); diff --git a/jit/jit-rules-x86.ins b/jit/jit-rules-x86.ins index e584da7..5009c04 100644 --- a/jit/jit-rules-x86.ins +++ b/jit/jit-rules-x86.ins @@ -17,18 +17,23 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +%regclass reg x86_reg +%regclass breg x86_breg +%regclass freg x86_freg +%lregclass lreg x86_lreg /* * Conversion opcodes. */ JIT_OP_TRUNC_SBYTE: - [=reg, reg("eax"|"ecx"|"edx"|"ebx")] -> { + [=reg, breg] -> { x86_widen_reg(inst, $1, $2, 1, 0); } JIT_OP_TRUNC_UBYTE: - [=reg, reg("eax"|"ecx"|"edx"|"ebx")] -> { + [=reg, breg] -> { x86_widen_reg(inst, $1, $2, 0, 0); } @@ -147,7 +152,7 @@ JIT_OP_INT_TO_NFLOAT: } JIT_OP_UINT_TO_NFLOAT: - [=freg, reg, scratch("?")] -> { + [=freg, reg, scratch reg] -> { x86_clear_reg(inst, $3); x86_push_reg(inst, $3); x86_push_reg(inst, $2); @@ -189,7 +194,7 @@ JIT_OP_ULONG_TO_NFLOAT: more_space } JIT_OP_NFLOAT_TO_FLOAT32: stack - [=freg, freg] -> { + [freg] -> { x86_alu_reg_imm(inst, X86_SUB, X86_ESP, sizeof(void *)); x86_fst_membase(inst, X86_ESP, 0, 0, 1); x86_fld_membase(inst, X86_ESP, 0, 0); @@ -197,7 +202,7 @@ JIT_OP_NFLOAT_TO_FLOAT32: stack } JIT_OP_NFLOAT_TO_FLOAT64: stack - [=freg, freg] -> { + [freg] -> { x86_alu_reg_imm(inst, X86_SUB, X86_ESP, sizeof(jit_float64)); x86_fst_membase(inst, X86_ESP, 0, 1, 1); x86_fld_membase(inst, X86_ESP, 0, 1); @@ -224,7 +229,7 @@ JIT_OP_IADD: commutative x86_alu_reg_reg(inst, X86_ADD, $1, $2); } -JIT_OP_ISUB: binary +JIT_OP_ISUB: [reg, imm] -> { x86_alu_reg_imm(inst, X86_SUB, $1, $2); } @@ -543,12 +548,12 @@ JIT_OP_IDIV: more_space } x86_shift_reg_imm(inst, X86_SAR, $1, shift); } - [reg("eax"), imm, scratch("?", "edx")] -> { + [reg("eax"), imm, scratch reg, scratch reg("edx")] -> { x86_mov_reg_imm(inst, $3, $2); x86_cdq(inst); x86_div_reg(inst, $3, 1); } - [reg("eax"), reg, scratch("edx")] -> { + [reg("eax"), reg, scratch reg("edx")] -> { unsigned char *patch, *patch2; #ifndef JIT_USE_SIGNALS x86_alu_reg_reg(inst, X86_OR, $2, $2); @@ -585,12 +590,12 @@ JIT_OP_IDIV_UN: more_space } x86_shift_reg_imm(inst, X86_SHR, $1, shift); } - [reg("eax"), imm, scratch("?", "edx")] -> { + [reg("eax"), imm, scratch reg, scratch reg("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")] -> { + [reg("eax"), reg, scratch reg("edx")] -> { #ifndef JIT_USE_SIGNALS unsigned char *patch; x86_alu_reg_reg(inst, X86_OR, $2, $2); @@ -621,12 +626,12 @@ JIT_OP_IREM: more_space x86_patch(patch, inst); x86_clear_reg(inst, $1); } - [=reg("edx"), *reg("eax"), imm, scratch("?", "edx")] -> { + [=reg("edx"), *reg("eax"), imm, scratch reg, scratch reg("edx")] -> { x86_mov_reg_imm(inst, $4, $3); x86_cdq(inst); x86_div_reg(inst, $4, 1); } - [=reg("edx"), *reg("eax"), reg, scratch("edx")] -> { + [=reg("edx"), *reg("eax"), reg, scratch reg("edx")] -> { unsigned char *patch, *patch2; #ifndef JIT_USE_SIGNALS x86_alu_reg_reg(inst, X86_OR, $3, $3); @@ -659,12 +664,12 @@ JIT_OP_IREM_UN: more_space /* 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("?", "edx")] -> { + [=reg("edx"), *reg("eax"), imm, scratch reg, scratch reg("edx")] -> { x86_mov_reg_imm(inst, $4, $3); x86_clear_reg(inst, X86_EDX); x86_div_reg(inst, $4, 0); } - [=reg("edx"), *reg("eax"), reg, scratch("edx")] -> { + [=reg("edx"), *reg("eax"), reg, scratch reg("edx")] -> { #ifndef JIT_USE_SIGNALS unsigned char *patch; x86_alu_reg_reg(inst, X86_OR, $3, $3); @@ -677,7 +682,7 @@ JIT_OP_IREM_UN: more_space x86_div_reg(inst, $3, 0); } -JIT_OP_INEG: unary +JIT_OP_INEG: [reg] -> { x86_neg_reg(inst, $1); } @@ -705,7 +710,7 @@ JIT_OP_LADD: commutative x86_alu_reg_reg(inst, X86_ADC, %1, %2); } -JIT_OP_LSUB: binary +JIT_OP_LSUB: [lreg, imm] -> { jit_int value1 = ((jit_int *)($2))[0]; jit_int value2 = ((jit_int *)($2))[1]; @@ -728,7 +733,7 @@ JIT_OP_LSUB: binary x86_alu_reg_reg(inst, X86_SBB, %1, %2); } -JIT_OP_LNEG: unary +JIT_OP_LNEG: [lreg] -> { /* TODO: gcc generates the first variant while AoA suggests the second. Figure out if one @@ -744,36 +749,29 @@ JIT_OP_LNEG: unary #endif } -JIT_OP_FADD, JIT_OP_DADD, JIT_OP_NFADD: binary, stack +JIT_OP_FADD, JIT_OP_DADD, JIT_OP_NFADD: stack [freg, freg] -> { x86_fp_op_reg(inst, X86_FADD, 1, 1); } -JIT_OP_FSUB, JIT_OP_DSUB, JIT_OP_NFSUB: binary, stack +JIT_OP_FSUB, JIT_OP_DSUB, JIT_OP_NFSUB: stack [freg, freg] -> { x86_fp_op_reg(inst, X86_FSUB, 1, 1); } -JIT_OP_FMUL, JIT_OP_DMUL, JIT_OP_NFMUL: binary, stack +JIT_OP_FMUL, JIT_OP_DMUL, JIT_OP_NFMUL: stack [freg, freg] -> { x86_fp_op_reg(inst, X86_FMUL, 1, 1); } -JIT_OP_FDIV, JIT_OP_DDIV, JIT_OP_NFDIV: binary, stack +JIT_OP_FDIV, JIT_OP_DDIV, JIT_OP_NFDIV: stack [freg, freg] -> { x86_fp_op_reg(inst, X86_FDIV, 1, 1); } -JIT_OP_FREM, JIT_OP_DREM, JIT_OP_NFREM: binary, stack - [freg, freg] -> { +JIT_OP_FREM, JIT_OP_DREM, JIT_OP_NFREM: stack + [freg, freg, scratch reg("eax")] -> { unsigned char *label; - int save_eax = 0; - if(gen->contents[X86_REG_EAX].num_values > 0 || - gen->contents[X86_REG_EAX].used_for_temp) - { - save_eax = 1; - x86_push_reg(inst, X86_EAX); - } x86_fxch(inst, 1); label = inst; x86_fprem(inst); @@ -781,13 +779,9 @@ JIT_OP_FREM, JIT_OP_DREM, JIT_OP_NFREM: binary, stack x86_alu_reg_imm(inst, X86_AND, X86_EAX, 0x0400); x86_branch(inst, X86_CC_NZ, label, 0); x86_fstp(inst, 1); - if(save_eax) - { - x86_pop_reg(inst, X86_EAX); - } } -JIT_OP_FNEG, JIT_OP_DNEG, JIT_OP_NFNEG: unary, stack +JIT_OP_FNEG, JIT_OP_DNEG, JIT_OP_NFNEG: stack [freg] -> { x86_fchs(inst); } @@ -829,12 +823,12 @@ JIT_OP_IXOR: commutative x86_alu_reg_reg(inst, X86_XOR, $1, $2); } -JIT_OP_INOT: unary +JIT_OP_INOT: [reg] -> { x86_not_reg(inst, $1); } -JIT_OP_ISHL: binary +JIT_OP_ISHL: [reg, imm] -> { x86_shift_reg_imm(inst, X86_SHL, $1, ($2 & 0x1F)); } @@ -842,7 +836,7 @@ JIT_OP_ISHL: binary inst = shift_reg(inst, X86_SHL, $1, $2); } -JIT_OP_ISHR: binary +JIT_OP_ISHR: [reg, imm] -> { x86_shift_reg_imm(inst, X86_SAR, $1, ($2 & 0x1F)); } @@ -850,7 +844,7 @@ JIT_OP_ISHR: binary inst = shift_reg(inst, X86_SAR, $1, $2); } -JIT_OP_ISHR_UN: binary +JIT_OP_ISHR_UN: [reg, imm] -> { x86_shift_reg_imm(inst, X86_SHR, $1, ($2 & 0x1F)); } @@ -906,7 +900,7 @@ JIT_OP_LXOR: commutative x86_alu_reg_reg(inst, X86_XOR, %1, %2); } -JIT_OP_LNOT: binary +JIT_OP_LNOT: [lreg] -> { x86_not_reg(inst, $1); x86_not_reg(inst, %1); @@ -916,24 +910,24 @@ JIT_OP_LNOT: binary * Branch opcodes. */ -JIT_OP_BR: spill_before +JIT_OP_BR: branch [] -> { inst = output_branch(func, inst, 0xEB /* jmp */, insn); } -JIT_OP_BR_IFALSE: unary_branch +JIT_OP_BR_IFALSE: branch [reg] -> { x86_alu_reg_reg(inst, X86_OR, $1, $1); inst = output_branch(func, inst, 0x74 /* eq */, insn); } -JIT_OP_BR_ITRUE: unary_branch +JIT_OP_BR_ITRUE: branch [reg] -> { x86_alu_reg_reg(inst, X86_OR, $1, $1); inst = output_branch(func, inst, 0x75 /* ne */, insn); } -JIT_OP_BR_IEQ: binary_branch +JIT_OP_BR_IEQ: branch [reg, immzero] -> { x86_alu_reg_reg(inst, X86_OR, $1, $1); inst = output_branch(func, inst, 0x74 /* eq */, insn); @@ -951,7 +945,7 @@ JIT_OP_BR_IEQ: binary_branch inst = output_branch(func, inst, 0x74 /* eq */, insn); } -JIT_OP_BR_INE: binary_branch +JIT_OP_BR_INE: branch [reg, immzero] -> { x86_alu_reg_reg(inst, X86_OR, $1, $1); inst = output_branch(func, inst, 0x75 /* ne */, insn); @@ -969,7 +963,7 @@ JIT_OP_BR_INE: binary_branch inst = output_branch(func, inst, 0x75 /* ne */, insn); } -JIT_OP_BR_ILT: binary_branch +JIT_OP_BR_ILT: branch [reg, imm] -> { x86_alu_reg_imm(inst, X86_CMP, $1, $2); inst = output_branch(func, inst, 0x7C /* lt */, insn); @@ -983,7 +977,7 @@ JIT_OP_BR_ILT: binary_branch inst = output_branch(func, inst, 0x7C /* lt */, insn); } -JIT_OP_BR_ILT_UN: binary_branch +JIT_OP_BR_ILT_UN: branch [reg, imm] -> { x86_alu_reg_imm(inst, X86_CMP, $1, $2); inst = output_branch(func, inst, 0x72 /* lt_un */, insn); @@ -997,7 +991,7 @@ JIT_OP_BR_ILT_UN: binary_branch inst = output_branch(func, inst, 0x72 /* lt_un */, insn); } -JIT_OP_BR_ILE: binary_branch +JIT_OP_BR_ILE: branch [reg, imm] -> { x86_alu_reg_imm(inst, X86_CMP, $1, $2); inst = output_branch(func, inst, 0x7E /* le */, insn); @@ -1011,7 +1005,7 @@ JIT_OP_BR_ILE: binary_branch inst = output_branch(func, inst, 0x7E /* le */, insn); } -JIT_OP_BR_ILE_UN: binary_branch +JIT_OP_BR_ILE_UN: branch [reg, imm] -> { x86_alu_reg_imm(inst, X86_CMP, $1, $2); inst = output_branch(func, inst, 0x76 /* le_un */, insn); @@ -1025,7 +1019,7 @@ JIT_OP_BR_ILE_UN: binary_branch inst = output_branch(func, inst, 0x76 /* le_un */, insn); } -JIT_OP_BR_IGT: binary_branch +JIT_OP_BR_IGT: branch [reg, imm] -> { x86_alu_reg_imm(inst, X86_CMP, $1, $2); inst = output_branch(func, inst, 0x7F /* gt */, insn); @@ -1039,7 +1033,7 @@ JIT_OP_BR_IGT: binary_branch inst = output_branch(func, inst, 0x7F /* gt */, insn); } -JIT_OP_BR_IGT_UN: binary_branch +JIT_OP_BR_IGT_UN: branch [reg, imm] -> { x86_alu_reg_imm(inst, X86_CMP, $1, $2); inst = output_branch(func, inst, 0x77 /* gt_un */, insn); @@ -1053,7 +1047,7 @@ JIT_OP_BR_IGT_UN: binary_branch inst = output_branch(func, inst, 0x77 /* gt_un */, insn); } -JIT_OP_BR_IGE: binary_branch +JIT_OP_BR_IGE: branch [reg, imm] -> { x86_alu_reg_imm(inst, X86_CMP, $1, $2); inst = output_branch(func, inst, 0x7D /* ge */, insn); @@ -1067,7 +1061,7 @@ JIT_OP_BR_IGE: binary_branch inst = output_branch(func, inst, 0x7D /* ge */, insn); } -JIT_OP_BR_IGE_UN: binary_branch +JIT_OP_BR_IGE_UN: branch [reg, imm] -> { x86_alu_reg_imm(inst, X86_CMP, $1, $2); inst = output_branch(func, inst, 0x73 /* ge_un */, insn); @@ -1237,29 +1231,29 @@ JIT_OP_IGE_UN: * Mathematical opcodes. */ -JIT_OP_FATAN, JIT_OP_DATAN, JIT_OP_NFATAN: unary, stack, only - [freg] -> { +JIT_OP_FATAN, JIT_OP_DATAN, JIT_OP_NFATAN: stack + [freg, clobber(freg)] -> { x86_fld1(inst); x86_fpatan(inst); x86_fldz(inst); x86_fp_op_reg(inst, X86_FADD, 1, 1); } -JIT_OP_FCOS, JIT_OP_DCOS, JIT_OP_NFCOS: unary, stack, only - [freg] -> { +JIT_OP_FCOS, JIT_OP_DCOS, JIT_OP_NFCOS: stack + [freg, clobber(freg)] -> { x86_fcos(inst); x86_fldz(inst); x86_fp_op_reg(inst, X86_FADD, 1, 1); } -JIT_OP_FSIN, JIT_OP_DSIN, JIT_OP_NFSIN: unary, stack, only - [freg] -> { +JIT_OP_FSIN, JIT_OP_DSIN, JIT_OP_NFSIN: stack + [freg, clobber(freg)] -> { x86_fsin(inst); x86_fldz(inst); x86_fp_op_reg(inst, X86_FADD, 1, 1); } -JIT_OP_FSQRT, JIT_OP_DSQRT, JIT_OP_NFSQRT: unary, stack +JIT_OP_FSQRT, JIT_OP_DSQRT, JIT_OP_NFSQRT: stack [freg] -> { x86_fsqrt(inst); } @@ -1269,14 +1263,14 @@ JIT_OP_FSQRT, JIT_OP_DSQRT, JIT_OP_NFSQRT: unary, stack */ JIT_OP_IABS: - [reg("eax"), scratch("edx")] -> { + [reg("eax"), scratch reg("edx")] -> { x86_cdq(inst); x86_alu_reg_reg(inst, X86_XOR, $1, $2); x86_alu_reg_reg(inst, X86_SUB, $1, $2); } JIT_OP_LABS: - [lreg, scratch("?")] -> { + [lreg, scratch reg] -> { x86_mov_reg_reg(inst, $2, %1, 4); x86_shift_reg_imm(inst, X86_SAR, $2, 31); x86_alu_reg_reg(inst, X86_XOR, $1, $2); @@ -1285,7 +1279,7 @@ JIT_OP_LABS: x86_alu_reg_reg(inst, X86_SBB, %1, $2); } -JIT_OP_FABS, JIT_OP_DABS, JIT_OP_NFABS: unary, stack +JIT_OP_FABS, JIT_OP_DABS, JIT_OP_NFABS: stack [freg] -> { x86_fabs(inst); } @@ -1329,7 +1323,7 @@ JIT_OP_LSIGN: * Pointer check opcodes. */ -JIT_OP_CHECK_NULL: unary_note +JIT_OP_CHECK_NULL: note [reg] -> { unsigned char *patch; x86_alu_reg_reg(inst, X86_OR, $1, $1); @@ -1398,32 +1392,35 @@ JIT_OP_RETURN: inst = jump_to_epilog(gen, inst, block); } -JIT_OP_RETURN_INT: unary_note +JIT_OP_RETURN_INT: note [reg("eax")] -> { inst = jump_to_epilog(gen, inst, block); } -JIT_OP_RETURN_LONG: unary_note +JIT_OP_RETURN_LONG: note [lreg("eax":"edx")] -> { inst = jump_to_epilog(gen, inst, block); } -JIT_OP_RETURN_FLOAT32: unary_note, stack, only - [freg] -> { +JIT_OP_RETURN_FLOAT32: note, stack + [freg, clobber(freg)] -> { + /* clobber(freg) frees all registers on the fp stack */ inst = jump_to_epilog(gen, inst, block); } -JIT_OP_RETURN_FLOAT64: unary_note, stack, only - [freg] -> { +JIT_OP_RETURN_FLOAT64: note, stack + [freg, clobber(freg)] -> { + /* clobber(freg) frees all registers on the fp stack */ inst = jump_to_epilog(gen, inst, block); } -JIT_OP_RETURN_NFLOAT: unary_note, stack, only - [freg] -> { +JIT_OP_RETURN_NFLOAT: note, stack + [freg, clobber(freg)] -> { + /* clobber(freg) frees all registers on the fp stack */ inst = jump_to_epilog(gen, inst, block); } -JIT_OP_RETURN_SMALL_STRUCT: binary_note +JIT_OP_RETURN_SMALL_STRUCT: note [reg, imm] -> { switch($2) { @@ -1520,7 +1517,7 @@ JIT_OP_RETURN_SMALL_STRUCT: binary_note inst = jump_to_epilog(gen, inst, block); } -JIT_OP_SETUP_FOR_NESTED: spill_before +JIT_OP_SETUP_FOR_NESTED: branch [] -> { jit_nint nest_reg = jit_value_get_nint_constant(insn->value1); if(nest_reg == -1) @@ -1534,7 +1531,7 @@ JIT_OP_SETUP_FOR_NESTED: spill_before } } -JIT_OP_SETUP_FOR_SIBLING: spill_before +JIT_OP_SETUP_FOR_SIBLING: branch [] -> { jit_value_t parent; jit_nint level = jit_value_get_nint_constant(insn->value1); @@ -1615,7 +1612,7 @@ JIT_OP_IMPORT: manual * Exception handling. */ -JIT_OP_THROW: unary_branch +JIT_OP_THROW: branch [reg] -> { x86_push_reg(inst, $1); if(func->builder->setjmp_value != 0) @@ -1664,13 +1661,13 @@ JIT_OP_LOAD_EXCEPTION_PC: manual JIT_OP_ENTER_FINALLY: manual [] -> { /* Nothing to do here: return address on the stack */ } -JIT_OP_LEAVE_FINALLY: spill_before +JIT_OP_LEAVE_FINALLY: branch [] -> { /* The "finally" return address is on the stack */ x86_ret(inst); } -JIT_OP_CALL_FINALLY: spill_before +JIT_OP_CALL_FINALLY: branch [] -> { jit_block_t block; @@ -1769,28 +1766,17 @@ JIT_OP_COPY_FLOAT64: copy, stack JIT_OP_COPY_NFLOAT: copy, stack [freg] -> {} -JIT_OP_COPY_STRUCT: manual, spill_before - [] -> { - unsigned char *inst; - _jit_gen_fix_value(insn->dest); - _jit_gen_fix_value(insn->value1); - inst = gen->posn.ptr; - if(!jit_cache_check_for_n(&(gen->posn), 128)) - { - jit_cache_mark_full(&(gen->posn)); - return; - } - inst = memory_copy(gen, inst, X86_EBP, insn->dest->frame_offset, - X86_EBP, insn->value1->frame_offset, - jit_type_get_size(jit_value_get_type(insn->dest))); - gen->posn.ptr = inst; +JIT_OP_COPY_STRUCT: + [=frame, frame, clobber(reg)] -> { + inst = memory_copy(gen, inst, X86_EBP, $1, X86_EBP, $2, + jit_type_get_size(jit_value_get_type(insn->dest))); } JIT_OP_COPY_STORE_BYTE: [=frame, imm] -> { x86_mov_membase_imm(inst, X86_EBP, $1, $2, 1); } - [=frame, reg("eax"|"ecx"|"edx"|"ebx")] -> { + [=frame, breg] -> { x86_mov_membase_reg(inst, X86_EBP, $1, $2, 1); } @@ -1812,9 +1798,11 @@ JIT_OP_ADDRESS_OF: */ JIT_OP_RETURN_REG: manual - [] -> { /* Nothing to do here */ } + [] -> { + /* Nothing to do here */; + } -JIT_OP_PUSH_INT: unary_note +JIT_OP_PUSH_INT: note [imm] -> { x86_push_imm(inst, $1); gen->stack_changed = 1; @@ -1828,7 +1816,7 @@ JIT_OP_PUSH_INT: unary_note gen->stack_changed = 1; } -JIT_OP_PUSH_LONG: unary_note +JIT_OP_PUSH_LONG: note [imm] -> { x86_push_imm(inst, ((jit_int *)($1))[1]); x86_push_imm(inst, ((jit_int *)($1))[0]); @@ -1845,7 +1833,7 @@ JIT_OP_PUSH_LONG: unary_note gen->stack_changed = 1; } -JIT_OP_PUSH_FLOAT32: unary_note, stack +JIT_OP_PUSH_FLOAT32: note, stack [imm] -> { jit_int *ptr = (jit_int *)($1); x86_push_imm(inst, ptr[0]); @@ -1861,7 +1849,7 @@ JIT_OP_PUSH_FLOAT32: unary_note, stack gen->stack_changed = 1; } -JIT_OP_PUSH_FLOAT64: unary_note, stack +JIT_OP_PUSH_FLOAT64: note, stack [imm] -> { jit_int *ptr = (jit_int *)($1); x86_push_imm(inst, ptr[1]); @@ -1879,7 +1867,7 @@ JIT_OP_PUSH_FLOAT64: unary_note, stack gen->stack_changed = 1; } -JIT_OP_PUSH_NFLOAT: unary_note, stack +JIT_OP_PUSH_NFLOAT: note, stack [imm] -> { jit_int *ptr = (jit_int *)($1); if(sizeof(jit_nfloat) != sizeof(jit_float64)) @@ -1913,8 +1901,8 @@ JIT_OP_PUSH_NFLOAT: unary_note, stack gen->stack_changed = 1; } -JIT_OP_PUSH_STRUCT: unary_branch, more_space - [reg] -> { +JIT_OP_PUSH_STRUCT: note, more_space + [reg, clobber(reg)] -> { jit_nuint size; size = (jit_nuint)jit_value_get_nint_constant(insn->value2); if((size % sizeof(void *)) == 0 && size <= 4 * sizeof(void *)) @@ -2013,25 +2001,23 @@ JIT_OP_LOAD_RELATIVE_NFLOAT: x86_fld_membase(inst, $2, $3, 1); } -JIT_OP_LOAD_RELATIVE_STRUCT: unary_branch, more_space - [reg] -> { - _jit_gen_fix_value(insn->dest); - inst = memory_copy(gen, inst, X86_EBP, insn->dest->frame_offset, - $1, jit_value_get_nint_constant(insn->value2), - jit_type_get_size(jit_value_get_type(insn->dest))); +JIT_OP_LOAD_RELATIVE_STRUCT: more_space + [=frame, reg, imm, clobber(reg)] -> { + inst = memory_copy(gen, inst, X86_EBP, $1, $2, $3, + jit_type_get_size(jit_value_get_type(insn->dest))); } JIT_OP_STORE_RELATIVE_BYTE: ternary [imm, imm, imm] -> { x86_mov_mem_imm(inst, $1 + $3, $2, 1); } - [imm, reg("eax"|"ecx"|"edx"|"ebx"), imm] -> { + [imm, breg, imm] -> { x86_mov_mem_reg(inst, $1 + $3, $2, 1); } [reg, imm, imm] -> { x86_mov_membase_imm(inst, $1, $3, $2, 1); } - [reg, reg("eax"|"ecx"|"edx"|"ebx"), imm] -> { + [reg, breg, imm] -> { x86_mov_membase_reg(inst, $1, $3, $2, 1); } @@ -2068,7 +2054,7 @@ JIT_OP_STORE_RELATIVE_LONG: ternary x86_mov_membase_imm(inst, $1, $3, *(int *)($2), 4); x86_mov_membase_imm(inst, $1, $3 + 4, *(int *)($2 + 4), 4); } - [reg, local, imm, scratch("?")] -> { + [reg, local, imm, scratch reg] -> { x86_mov_reg_membase(inst, $4, X86_EBP, $2, 4); x86_mov_membase_reg(inst, $1, $3, $4, 4); x86_mov_reg_membase(inst, $4, X86_EBP, $2 + 4, 4); @@ -2138,11 +2124,11 @@ JIT_OP_STORE_RELATIVE_STRUCT: manual gen->posn.ptr = inst; } -JIT_OP_ADD_RELATIVE: unary - [reg] -> { +JIT_OP_ADD_RELATIVE: + [reg, imm] -> { if(insn->value2->address != 0) { - x86_alu_reg_imm(inst, X86_ADD, $1, insn->value2->address); + x86_alu_reg_imm(inst, X86_ADD, $1, $2); } } @@ -2211,7 +2197,7 @@ JIT_OP_LOAD_ELEMENT_NFLOAT: } JIT_OP_STORE_ELEMENT_BYTE: ternary - [reg, reg, reg("eax"|"ecx"|"edx"|"ebx")] -> { + [reg, reg, breg] -> { x86_mov_memindex_reg(inst, $1, 0, $2, 0, $3, 1); } @@ -2230,7 +2216,7 @@ JIT_OP_STORE_ELEMENT_LONG: ternary x86_mov_memindex_imm(inst, $1, 0, $2, 3, *(int *)($3), 4); x86_mov_memindex_imm(inst, $1, 4, $2, 3, *(int *)($3 + 4), 4); } - [reg, reg, local, scratch("?")] -> { + [reg, reg, local, scratch reg] -> { x86_mov_reg_membase(inst, $4, X86_EBP, $3, 4); x86_mov_memindex_reg(inst, $1, 0, $2, 3, $4, 4); x86_mov_reg_membase(inst, $4, X86_EBP, $3 + 4, 4); @@ -2268,8 +2254,7 @@ JIT_OP_STORE_ELEMENT_NFLOAT: ternary JIT_OP_MEMCPY: ternary [any, any, imm, if("$3 <= 0")] -> { } - [reg, reg, imm, if("$3 <= 32"), - scratch("eax" | "ecx" | "edx" | "ebx"), space("32 + $3 * 4")] -> { + [reg, reg, imm, scratch breg, if("$3 <= 32"), space("32 + $3 * 4")] -> { int disp; disp = 0; while($3 >= (disp + 4)) @@ -2328,7 +2313,7 @@ JIT_OP_MEMSET: ternary x86_mov_membase_imm(inst, $1, disp, $2, 1); } } - [reg, reg("eax"|"ecx"|"edx"|"ebx"), imm, if("$3 < 4")] -> { + [reg, breg, imm, if("$3 < 4")] -> { x86_mov_membase_reg(inst, $1, 0, $2, 1); if($3 > 1) { @@ -2339,7 +2324,7 @@ JIT_OP_MEMSET: ternary } } } - [reg, +reg, imm, scratch("?"), + [reg, +reg, imm, scratch reg, if("$3 <= 32 && ($3 % 2) == 0"), space("32 + $3 * 4")] -> { int disp; x86_mov_reg_reg(inst, $4, $2, 4); @@ -2359,7 +2344,7 @@ JIT_OP_MEMSET: ternary x86_mov_membase_reg(inst, $1, disp, $2, 2); } } - [reg, +reg("eax"|"ecx"|"edx"|"ebx"), imm, scratch("?"), + [reg, +breg, imm, scratch reg, if("$3 <= 32 && ($3 % 2) != 0"), space("32 + $3 * 4")] -> { int disp; x86_mov_reg_reg(inst, $4, $2, 4); @@ -2396,7 +2381,7 @@ JIT_OP_MEMSET: ternary * Allocate memory from the stack. */ -JIT_OP_ALLOCA: unary +JIT_OP_ALLOCA: [reg] -> { x86_alu_reg_imm(inst, X86_ADD, $1, 15); x86_alu_reg_imm(inst, X86_AND, $1, ~15); @@ -2405,8 +2390,8 @@ JIT_OP_ALLOCA: unary gen->stack_changed = 1; } -JIT_OP_JUMP_TABLE: ternary - [reg, imm, imm, clobber("*"), space("32 + sizeof(void) * $3")] -> { +JIT_OP_JUMP_TABLE: ternary, branch + [reg, imm, imm, space("32 + sizeof(void) * $3")] -> { unsigned char *patch_jump_table; unsigned char *patch_fall_through; int index; diff --git a/tools/gen-rules-parser.y b/tools/gen-rules-parser.y index 3162210..22384ba 100644 --- a/tools/gen-rules-parser.y +++ b/tools/gen-rules-parser.y @@ -103,32 +103,26 @@ static int gensel_reserve_more_space = 128; #define MAX_PATTERN (MAX_INPUT + MAX_SCRATCH) /* - * Options. + * Rule Options. */ -#define GENSEL_OPT_BINARY 1 -#define GENSEL_OPT_UNARY 2 -#define GENSEL_OPT_UNARY_BRANCH 3 -#define GENSEL_OPT_BINARY_BRANCH 4 -#define GENSEL_OPT_UNARY_NOTE 5 -#define GENSEL_OPT_BINARY_NOTE 6 -#define GENSEL_OPT_TERNARY 7 -#define GENSEL_OPT_STACK 8 -#define GENSEL_OPT_ONLY 9 -#define GENSEL_OPT_COPY 10 -#define GENSEL_OPT_X87ARITH 11 -#define GENSEL_OPT_COMMUTATIVE 12 -#define GENSEL_OPT_REVERSIBLE 13 - -#define GENSEL_OPT_MANUAL 14 -#define GENSEL_OPT_MORE_SPACE 15 -#define GENSEL_OPT_SPILL_BEFORE 16 +#define GENSEL_OPT_TERNARY 1 +#define GENSEL_OPT_BRANCH 2 +#define GENSEL_OPT_NOTE 3 +#define GENSEL_OPT_COPY 4 +#define GENSEL_OPT_COMMUTATIVE 5 +#define GENSEL_OPT_STACK 6 +#define GENSEL_OPT_X87_ARITH 7 +#define GENSEL_OPT_X87_ARITH_REVERSIBLE 8 + +#define GENSEL_OPT_MANUAL 9 +#define GENSEL_OPT_MORE_SPACE 10 /* * Pattern values. */ -#define GENSEL_PATT_REG 1 -#define GENSEL_PATT_LREG 2 -#define GENSEL_PATT_FREG 3 +#define GENSEL_PATT_ANY 1 +#define GENSEL_PATT_REG 2 +#define GENSEL_PATT_LREG 3 #define GENSEL_PATT_IMM 4 #define GENSEL_PATT_IMMZERO 5 #define GENSEL_PATT_IMMS8 6 @@ -141,20 +135,27 @@ static int gensel_reserve_more_space = 128; #define GENSEL_PATT_CLOBBER 13 #define GENSEL_PATT_IF 14 #define GENSEL_PATT_SPACE 15 -#define GENSEL_PATT_ANY 16 /* - * Register flags. + * Value types. */ -#define GENSEL_FLAG_DEST 1 -#define GENSEL_FLAG_CLOBBER 2 -#define GENSEL_FLAG_EARLY_CLOBBER 3 +#define GENSEL_VALUE_STRING 1 +#define GENSEL_VALUE_REGCLASS 2 +#define GENSEL_VALUE_ALL 3 +#define GENSEL_VALUE_CLOBBER 4 +#define GENSEL_VALUE_EARLY_CLOBBER 5 /* - * Value Type. + * Register class. */ -#define GENSEL_VALUE_STRING 1 -#define GENSEL_VALUE_CHOICE 2 +typedef struct gensel_regclass *gensel_regclass_t; +struct gensel_regclass +{ + char *id; + char *def; + int is_long; + gensel_regclass_t next; +}; /* * Option value. @@ -163,11 +164,7 @@ typedef struct gensel_value *gensel_value_t; struct gensel_value { int type; - union - { - char *value; - gensel_value_t children; - }; + void *value; gensel_value_t next; }; @@ -178,7 +175,6 @@ typedef struct gensel_option *gensel_option_t; struct gensel_option { int option; - int flags; gensel_value_t values; gensel_option_t next; }; @@ -189,6 +185,7 @@ struct gensel_option typedef struct gensel_clause *gensel_clause_t; struct gensel_clause { + int dest; gensel_option_t pattern; char *filename; long linenum; @@ -214,9 +211,55 @@ static char *gensel_imm_names[] = { static char *gensel_local_names[] = { "local_offset", "local_offset2", "local_offset3" }; -static char *gensel_reg_flags[] = { - "0", "0", "_JIT_REGS_CLOBBER", "_JIT_REGS_EARLY_CLOBBER" -}; + +/* + * Register classes. + */ +static gensel_regclass_t gensel_regclass_list; + +/* + * Create a register class. + */ +static void +gensel_create_regclass(char *id, char *def, int is_long) +{ + gensel_regclass_t rp; + + rp = (gensel_regclass_t) malloc(sizeof(struct gensel_regclass)); + if(!rp) + { + exit(1); + } + + rp->id = id; + rp->def = def; + rp->is_long = is_long; + rp->next = gensel_regclass_list; + + gensel_regclass_list = rp; +} + +gensel_regclass_t +gensel_lookup_regclass(char *id) +{ + gensel_regclass_t rp; + + rp = gensel_regclass_list; + for(;;) + { + if(!rp) + { + gensel_error( + gensel_filename, gensel_linenum, + "invalid register class"); + } + if(strcmp(id, rp->id) == 0) + { + return rp; + } + rp = rp->next; + } +} /* * Create a value. @@ -233,7 +276,9 @@ gensel_create_value(int type) } vp->type = type; + vp->value = 0; vp->next = 0; + return vp; } @@ -241,25 +286,27 @@ gensel_create_value(int type) * Create string value. */ static gensel_value_t -gensel_create_string(char *value) +gensel_create_string_value(char *value) { gensel_value_t vp; vp = gensel_create_value(GENSEL_VALUE_STRING); vp->value = value; + return vp; } /* - * Create choice value. + * Create string value. */ static gensel_value_t -gensel_create_choice(gensel_value_t children) +gensel_create_regclass_value(char *value) { gensel_value_t vp; - vp = gensel_create_value(GENSEL_VALUE_CHOICE); - vp->children = children; + vp = gensel_create_value(GENSEL_VALUE_REGCLASS); + vp->value = gensel_lookup_regclass(value); + return vp; } @@ -267,7 +314,7 @@ gensel_create_choice(gensel_value_t children) * Create an option. */ static gensel_option_t -gensel_create_option_2(int option, int flags, gensel_value_t values) +gensel_create_option(int option, gensel_value_t values) { gensel_option_t op; @@ -278,19 +325,48 @@ gensel_create_option_2(int option, int flags, gensel_value_t values) } op->option = option; - op->flags = flags; op->values = values; op->next = 0; return op; } /* - * Create an option with no flags. + * Create a register pattern element. */ static gensel_option_t -gensel_create_option(int option, gensel_value_t values) +gensel_create_register( + int flags, + gensel_value_t value, + gensel_value_t values) { - return gensel_create_option_2(option, 0, values); + gensel_regclass_t regclass; + + if(flags) + { + value->next = gensel_create_value(flags); + value->next->next = values; + } + else + { + value->next = values; + } + + regclass = value->value; + return gensel_create_option( + regclass->is_long ? GENSEL_PATT_LREG : GENSEL_PATT_REG, + value); +} + +/* + * Create a scratch register pattern element. + */ +static gensel_option_t +gensel_create_scratch( + gensel_value_t regclass, + gensel_value_t values) +{ + regclass->next = values; + return gensel_create_option(GENSEL_PATT_SCRATCH, regclass); } /* @@ -307,10 +383,6 @@ gensel_free_values(gensel_value_t values) { free(values->value); } - else - { - gensel_free_values(values->children); - } free(values); values = next; } @@ -365,22 +437,20 @@ gensel_search_option(gensel_option_t options, int tag) /* * Declare the register variables that are needed for a set of clauses. */ -static void gensel_declare_regs(gensel_clause_t clauses, gensel_option_t options) +static void +gensel_declare_regs(gensel_clause_t clauses, gensel_option_t options) { gensel_option_t pattern; - gensel_value_t values; int regs, max_regs; int other_regs_mask; int imms, max_imms; int locals, max_locals; int scratch, others; - int have_regset; max_regs = 0; other_regs_mask = 0; max_imms = 0; max_locals = 0; - have_regset = 0; while(clauses != 0) { regs = 0; @@ -398,23 +468,12 @@ static void gensel_declare_regs(gensel_clause_t clauses, gensel_option_t options break; case GENSEL_PATT_REG: - case GENSEL_PATT_FREG: ++regs; - if(pattern->values - && pattern->values->type != GENSEL_VALUE_STRING) - { - have_regset = 1; - } break; case GENSEL_PATT_LREG: other_regs_mask |= (1 << regs); ++regs; - if(pattern->values - && pattern->values->type != GENSEL_VALUE_STRING) - { - have_regset = 1; - } break; case GENSEL_PATT_IMMZERO: @@ -435,16 +494,7 @@ static void gensel_declare_regs(gensel_clause_t clauses, gensel_option_t options break; case GENSEL_PATT_SCRATCH: - values = pattern->values; - while(values) - { - ++scratch; - if(values->type != GENSEL_VALUE_STRING) - { - have_regset = 1; - } - values = values->next; - } + ++scratch; } pattern = pattern->next; } @@ -536,10 +586,6 @@ static void gensel_declare_regs(gensel_clause_t clauses, gensel_option_t options printf("\tjit_nint local_offset, local_offset2, local_offset3;\n"); break; } - if(have_regset) - { - printf("\tjit_regused_t regset;\n"); - } } /* @@ -553,7 +599,6 @@ gensel_contains_registers(gensel_option_t pattern) switch(pattern->option) { case GENSEL_PATT_REG: - case GENSEL_PATT_FREG: case GENSEL_PATT_LREG: case GENSEL_PATT_SCRATCH: case GENSEL_PATT_CLOBBER: @@ -565,52 +610,22 @@ gensel_contains_registers(gensel_option_t pattern) } /* - * Check if the pattern contains the dest register and if it is - * defined correctly. + * Returns first register in the pattern if any. */ -static int -gensel_contains_free_dest(gensel_clause_t clauses, gensel_option_t pattern) +static gensel_option_t +gensel_get_first_register(gensel_option_t pattern) { - int found, index; - - found = 0; - index = 0; while(pattern) { switch(pattern->option) { case GENSEL_PATT_REG: - case GENSEL_PATT_FREG: case GENSEL_PATT_LREG: - case GENSEL_PATT_LOCAL: - case GENSEL_PATT_FRAME: - if(pattern->flags == GENSEL_FLAG_DEST) - { - if(index != 0) - { - gensel_error( - clauses->filename, - clauses->linenum, - "The destination must be the first pattern element."); - } - found = 1; - } - ++index; - break; - - case GENSEL_PATT_ANY: - case GENSEL_PATT_IMMZERO: - case GENSEL_PATT_IMM: - case GENSEL_PATT_IMMS8: - case GENSEL_PATT_IMMU8: - case GENSEL_PATT_IMMS16: - case GENSEL_PATT_IMMU16: - ++index; - break; + return pattern; } pattern = pattern->next; } - return found; + return 0; } static void @@ -654,7 +669,6 @@ gensel_build_arg_index( break; case GENSEL_PATT_REG: - case GENSEL_PATT_FREG: case GENSEL_PATT_LREG: case GENSEL_PATT_LOCAL: case GENSEL_PATT_FRAME: @@ -705,7 +719,6 @@ gensel_build_imm_arg_index( { case GENSEL_PATT_ANY: case GENSEL_PATT_REG: - case GENSEL_PATT_FREG: case GENSEL_PATT_LREG: case GENSEL_PATT_LOCAL: case GENSEL_PATT_FRAME: @@ -748,7 +761,6 @@ gensel_build_var_index( char *names[MAX_PATTERN], char *other_names[MAX_PATTERN]) { - gensel_value_t values; int regs, imms, locals, index; gensel_init_names(MAX_PATTERN, names, other_names); @@ -766,7 +778,6 @@ gensel_build_var_index( break; case GENSEL_PATT_REG: - case GENSEL_PATT_FREG: names[index] = gensel_reg_names[regs]; ++regs; ++index; @@ -801,14 +812,9 @@ gensel_build_var_index( break; case GENSEL_PATT_SCRATCH: - values = pattern->values; - while(values) - { - names[index] = gensel_reg_names[regs]; - ++regs; - ++index; - values = values->next; - } + names[index] = gensel_reg_names[regs]; + ++regs; + ++index; } pattern = pattern->next; } @@ -836,11 +842,7 @@ gensel_output_code( } while(*code != '\0') { -#if 0 - first = free_dest ? '0' : '1'; -#else first = '1'; -#endif if(*code == '$' && code[1] >= first && code[1] < (first + MAX_PATTERN)) { index = code[1] - first; @@ -889,30 +891,75 @@ gensel_output_clause_code( gensel_output_code(clause->pattern, clause->code, names, other_names, free_dest, 0); } +static void +gensel_output_register(char *name, gensel_regclass_t regclass, gensel_value_t values) +{ + printf("\t\t_jit_regs_init_%s(®s, insn, ", name); + switch(values ? values->type : 0) + { + case GENSEL_VALUE_CLOBBER: + printf("_JIT_REGS_CLOBBER"); + values = values->next; + break; + case GENSEL_VALUE_EARLY_CLOBBER: + printf("_JIT_REGS_EARLY_CLOBBER"); + values = values->next; + break; + default: + printf("0"); + break; + } + printf(", %s);\n", regclass->def); + if(values && values->value) + { + char *reg; + reg = values->value; + if(values->next && values->next->value) + { + char *other_reg; + other_reg = values->next->value; + printf("\t\t_jit_regs_set_%s(gen, ®s, _jit_regs_lookup(\"%s\"), _jit_regs_lookup(\"%s\"));\n", + name, reg, other_reg); + } + else + { + printf("\t\t_jit_regs_set_%s(gen, ®s, _jit_regs_lookup(\"%s\"), -1);\n", + name, reg); + } + } +} + +/* + * Output value initialization code. + */ +static void +gensel_output_register_pattern(char *name, gensel_option_t pattern) +{ + gensel_output_register(name, pattern->values->value, pattern->values->next); +} + /* * Output the clauses for a rule. */ static void gensel_output_clauses(gensel_clause_t clauses, gensel_option_t options) { + char *name; char *args[MAX_INPUT]; char *names[MAX_PATTERN]; char *other_names[MAX_PATTERN]; gensel_clause_t clause; gensel_option_t pattern; gensel_option_t space, more_space; - gensel_value_t values, child; - int first, seen_option; + gensel_value_t values; int regs, imms, locals, scratch, index; - int clobber_all, ternary, free_dest; + int first, seen_option; + int ternary, free_dest; int contains_registers; + gensel_regclass_t regclass; /* If the clause is manual, then output it as-is */ if(gensel_search_option(options, GENSEL_OPT_MANUAL)) { - if(gensel_search_option(options, GENSEL_OPT_SPILL_BEFORE)) - { - printf("\t_jit_regs_spill_all(gen);\n"); - } gensel_init_names(MAX_PATTERN, names, other_names); gensel_output_clause_code(clauses, names, other_names, 0); return; @@ -936,10 +983,6 @@ static void gensel_output_clauses(gensel_clause_t clauses, gensel_option_t optio printf("\t_jit_regs_t regs;\n"); } gensel_declare_regs(clauses, options); - if(gensel_search_option(options, GENSEL_OPT_SPILL_BEFORE)) - { - printf("\t_jit_regs_spill_all(gen);\n"); - } ternary = (0 != gensel_search_option(options, GENSEL_OPT_TERNARY)); @@ -949,23 +992,7 @@ static void gensel_output_clauses(gensel_clause_t clauses, gensel_option_t optio while(clause) { contains_registers = gensel_contains_registers(clause->pattern); - free_dest = gensel_contains_free_dest(clauses, clause->pattern); - - clobber_all = 0; - pattern = gensel_search_option(clause->pattern, GENSEL_PATT_CLOBBER); - if(pattern) - { - values = pattern->values; - while(values) - { - if(values->value && strcmp(values->value, "*") == 0) - { - clobber_all = 1; - break; - } - values = values->next; - } - } + free_dest = clause->dest; gensel_build_arg_index(clause->pattern, 3, args, 0, ternary, free_dest); @@ -989,7 +1016,6 @@ static void gensel_output_clauses(gensel_clause_t clauses, gensel_option_t optio case GENSEL_PATT_REG: case GENSEL_PATT_LREG: - case GENSEL_PATT_FREG: /* Do not check if the value is in a register as the allocator will load them anyway as long as other @@ -1128,55 +1154,21 @@ static void gensel_output_clauses(gensel_clause_t clauses, gensel_option_t optio printf("\telse\n\t{\n"); } - if(gensel_search_option(options, GENSEL_OPT_BINARY_BRANCH) - || gensel_search_option(options, GENSEL_OPT_UNARY_BRANCH)) - { - /* Spill all other registers back to their original positions */ - if(contains_registers) - { - clobber_all = 1; - } - else - { - printf("\t\t_jit_regs_spill_all(gen);\n"); - } - } - if(contains_registers) { seen_option = 0; printf("\t\t_jit_regs_init(gen, ®s, "); - if(clobber_all) - { - seen_option = 1; - printf("_JIT_REGS_CLOBBER_ALL"); - } if(ternary) { - if(seen_option) - { - printf(" | "); - } - else - { - seen_option = 1; - } + seen_option = 1; printf("_JIT_REGS_TERNARY"); } - if(free_dest) + else if(free_dest) { - if(seen_option) - { - printf(" | "); - } - else - { - seen_option = 1; - } + seen_option = 1; printf("_JIT_REGS_FREE_DEST"); } - if(gensel_search_option(options, GENSEL_OPT_BINARY_BRANCH) - || gensel_search_option(options, GENSEL_OPT_UNARY_BRANCH)) + if(gensel_search_option(options, GENSEL_OPT_BRANCH)) { if(seen_option) { @@ -1212,7 +1204,7 @@ static void gensel_output_clauses(gensel_clause_t clauses, gensel_option_t optio } printf("_JIT_REGS_STACK"); } - if(gensel_search_option(options, GENSEL_OPT_ONLY)) + if(gensel_search_option(options, GENSEL_OPT_COMMUTATIVE)) { if(seen_option) { @@ -1222,9 +1214,10 @@ static void gensel_output_clauses(gensel_clause_t clauses, gensel_option_t optio { seen_option = 1; } - printf("_JIT_REGS_CLOBBER_STACK"); + printf("_JIT_REGS_COMMUTATIVE"); } - if(gensel_search_option(options, GENSEL_OPT_X87ARITH)) + /* x87 options */ + if(gensel_search_option(options, GENSEL_OPT_X87_ARITH)) { if(seen_option) { @@ -1236,7 +1229,7 @@ static void gensel_output_clauses(gensel_clause_t clauses, gensel_option_t optio } printf("_JIT_REGS_X87_ARITH"); } - if(gensel_search_option(options, GENSEL_OPT_COMMUTATIVE)) + else if(gensel_search_option(options, GENSEL_OPT_X87_ARITH_REVERSIBLE)) { if(seen_option) { @@ -1246,19 +1239,7 @@ static void gensel_output_clauses(gensel_clause_t clauses, gensel_option_t optio { seen_option = 1; } - printf("_JIT_REGS_COMMUTATIVE"); - } - if(gensel_search_option(options, GENSEL_OPT_REVERSIBLE)) - { - if(seen_option) - { - printf(" | "); - } - else - { - seen_option = 1; - } - printf("_JIT_REGS_REVERSIBLE"); + printf("_JIT_REGS_X87_ARITH_REVERSIBLE"); } if(!seen_option) { @@ -1267,17 +1248,17 @@ static void gensel_output_clauses(gensel_clause_t clauses, gensel_option_t optio printf(");\n"); if(!(ternary || free_dest - || gensel_search_option(options, GENSEL_OPT_BINARY_NOTE) - || gensel_search_option(options, GENSEL_OPT_BINARY_BRANCH) - || gensel_search_option(options, GENSEL_OPT_UNARY_NOTE) - || gensel_search_option(options, GENSEL_OPT_UNARY_BRANCH))) + || gensel_search_option(options, GENSEL_OPT_NOTE) + || gensel_search_option(options, GENSEL_OPT_BRANCH))) { - printf("\t\t_jit_regs_init_dest(®s, insn, 0);\n"); + pattern = gensel_get_first_register(clause->pattern); + gensel_output_register("dest", pattern ? pattern->values->value : 0, 0); } } regs = 0; index = 0; + scratch = 0; pattern = clause->pattern; while(pattern) { @@ -1288,72 +1269,8 @@ static void gensel_output_clauses(gensel_clause_t clauses, gensel_option_t optio break; case GENSEL_PATT_REG: - case GENSEL_PATT_FREG: - printf("\t\t_jit_regs_init_%s(®s, insn, %s);\n", - args[index], gensel_reg_flags[pattern->flags]); - if(pattern->values && pattern->values->value) - { - if(pattern->values->type == GENSEL_VALUE_STRING) - { - printf("\t\t_jit_regs_set_%s(gen, ®s, _jit_regs_lookup(\"%s\"), -1);\n", - args[index], pattern->values->value); - } - else - { - printf("\t\tregset = jit_regused_init;\n"); - child = pattern->values->children; - while(child) - { - printf("\t\t%s = _jit_regs_lookup(\"%s\");\n", - gensel_reg_names[regs], child->value); - printf("\t\tif(%s >= 0)\n", gensel_reg_names[regs]); - printf("\t\t\tjit_reg_set_used(regset, %s);\n", - gensel_reg_names[regs]); - child = child->next; - } - printf("\t\t_jit_regs_set_%s_from(®s, regset);\n", - args[index]); - } - } - ++regs; - ++index; - break; - case GENSEL_PATT_LREG: - printf("\t\t_jit_regs_init_%s(®s, insn, %s);\n", - args[index], gensel_reg_flags[pattern->flags]); - if(pattern->values && pattern->values->value) - { - if(pattern->values->type == GENSEL_VALUE_STRING) - { - if(pattern->values->next && pattern->values->next->value) - { - 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(gen, ®s, _jit_regs_lookup(\"%s\"), -1);\n", - args[index], pattern->values->value); - } - } - else - { - printf("\t\tregset = jit_regused_init;\n"); - child = pattern->values->children; - while(child) - { - printf("\t\t%s = _jit_regs_lookup(\"%s\");\n", - gensel_reg_names[regs], child->value); - printf("\t\tif(%s >= 0)\n", gensel_reg_names[regs]); - printf("\t\t\tjit_reg_set_used(regset, %s);\n", - gensel_reg_names[regs]); - child = child->next; - } - printf("\t\t_jit_regs_set_%s_from(®s, regset);\n", - args[index]); - } - } + gensel_output_register_pattern(args[index], pattern); ++regs; ++index; break; @@ -1370,59 +1287,52 @@ static void gensel_output_clauses(gensel_clause_t clauses, gensel_option_t optio case GENSEL_PATT_FRAME: printf("\t\t_jit_regs_force_out(gen, insn->%s, %d);\n", - args[index], (pattern->flags == GENSEL_FLAG_DEST)); + args[index], (free_dest && index == 0)); printf("\t\t_jit_gen_fix_value(insn->%s);\n", args[index]); ++index; break; case GENSEL_PATT_SCRATCH: - values = pattern->values; - while(values) + regclass = pattern->values->value; + printf("\t\t_jit_regs_add_scratch(®s, %s);\n", + regclass->def); + if(pattern->values->next && pattern->values->next->value) { - if(values->value - && (values->type != GENSEL_VALUE_STRING - || strcmp(values->value, "?") != 0)) - { - if(values->type == GENSEL_VALUE_STRING) - { - printf("\t\t_jit_regs_add_scratch(gen, ®s, _jit_regs_lookup(\"%s\"));\n", - values->value); - } - else - { - printf("\t\tregset = jit_regused_init;\n"); - child = values->children; - while(child) - { - printf("\t\t%s = _jit_regs_lookup(\"%s\");\n", - gensel_reg_names[regs], child->value); - printf("\t\tif(%s >= 0)\n", gensel_reg_names[regs]); - printf("\t\t\tjit_reg_set_used(regset, %s);\n", - gensel_reg_names[regs]); - child = child->next; - } - printf("\t\t_jit_regs_add_scratch_from(®s, regset);\n"); - } - } - else - { - printf("\t\t_jit_regs_add_scratch(gen, ®s, -1);\n"); - } - ++regs; - ++index; - values = values->next; + name = pattern->values->next->value; + printf("\t\t_jit_regs_set_scratch(gen, ®s, %d, _jit_regs_lookup(\"%s\"));\n", + scratch, name); } + ++regs; + ++scratch; + ++index; break; case GENSEL_PATT_CLOBBER: values = pattern->values; while(values) { - if(values->value && strcmp(values->value, "*") != 0) + if(!values->value) { - printf("\t\t_jit_regs_set_clobber(gen, ®s, _jit_regs_lookup(\"%s\"));\n", - values->value); + continue; + } + switch(values->type) + { + case GENSEL_VALUE_STRING: + name = values->value; + printf("\t\t_jit_regs_clobber(®s, _jit_regs_lookup(\"%s\"));\n", + name); + break; + + case GENSEL_VALUE_REGCLASS: + regclass = values->value; + printf("\t\t_jit_regs_clobber_class(gen, ®s, %s);\n", + regclass->def); + break; + + case GENSEL_VALUE_ALL: + printf("\t\t_jit_regs_clobber_all(gen, ®s);\n"); + break; } values = values->next; } @@ -1431,6 +1341,19 @@ static void gensel_output_clauses(gensel_clause_t clauses, gensel_option_t optio pattern = pattern->next; } + if(gensel_search_option(options, GENSEL_OPT_BRANCH)) + { + /* Spill all other registers back to their original positions */ + if(contains_registers) + { + printf("\t\t_jit_regs_clobber_all(gen, ®s);\n"); + } + else + { + printf("\t\t_jit_regs_spill_all(gen);\n"); + } + } + if(gensel_new_inst_type) { if(contains_registers) @@ -1510,17 +1433,16 @@ static void gensel_output_clauses(gensel_clause_t clauses, gensel_option_t optio break; case GENSEL_PATT_REG: - case GENSEL_PATT_FREG: - printf("\t\t%s = _jit_reg_info[_jit_regs_%s(®s)].cpu_reg;\n", + printf("\t\t%s = _jit_reg_info[_jit_regs_get_%s(®s)].cpu_reg;\n", gensel_reg_names[regs], args[index]); ++regs; ++index; break; case GENSEL_PATT_LREG: - printf("\t\t%s = _jit_reg_info[_jit_regs_%s(®s)].cpu_reg;\n", + printf("\t\t%s = _jit_reg_info[_jit_regs_get_%s(®s)].cpu_reg;\n", gensel_reg_names[regs], args[index]); - printf("\t\t%s = _jit_reg_info[_jit_regs_%s_other(®s)].cpu_reg;\n", + printf("\t\t%s = _jit_reg_info[_jit_regs_get_%s_other(®s)].cpu_reg;\n", gensel_other_reg_names[regs], args[index]); ++regs; ++index; @@ -1550,15 +1472,11 @@ static void gensel_output_clauses(gensel_clause_t clauses, gensel_option_t optio break; case GENSEL_PATT_SCRATCH: - values = pattern->values; - while(values) - { - printf("\t\t%s = _jit_reg_info[_jit_regs_scratch(®s, %d)].cpu_reg;\n", - gensel_reg_names[regs], scratch); - ++regs; - ++scratch; - values = values->next; - } + printf("\t\t%s = _jit_reg_info[_jit_regs_get_scratch(®s, %d)].cpu_reg;\n", + gensel_reg_names[regs], scratch); + ++regs; + ++scratch; + ++index; break; } @@ -1693,10 +1611,8 @@ static void gensel_output_supported(void) %token CODE_BLOCK "a code block" %token LITERAL "literal string" %token K_PTR "`->'" -%token K_ANY "any variable" -%token K_REG "word register" -%token K_LREG "long register" -%token K_FREG "float register" +%token K_ANY "any value" +%token K_ALL "all registers" %token K_IMM "immediate value" %token K_IMMZERO "immediate zero value" %token K_IMMS8 "immediate signed 8-bit value" @@ -1705,30 +1621,26 @@ static void gensel_output_supported(void) %token K_IMMU16 "immediate unsigned 16-bit value" %token K_LOCAL "local variable" %token K_FRAME "local variable forced out into the stack frame" -%token K_BINARY "`binary'" -%token K_UNARY "`unary'" -%token K_UNARY_BRANCH "`unary_branch'" -%token K_BINARY_BRANCH "`binary_branch'" -%token K_UNARY_NOTE "`unary_note'" -%token K_BINARY_NOTE "`binary_note'" +%token K_NOTE "`note'" %token K_TERNARY "`ternary'" -%token K_STACK "`stack'" -%token K_ONLY "`only'" +%token K_BRANCH "`branch'" %token K_COPY "`copy'" -%token K_X87ARITH "`x87arith'" %token K_COMMUTATIVE "`commutative'" -%token K_REVERSIBLE "`reversible'" %token K_IF "`if'" %token K_CLOBBER "`clobber'" %token K_SCRATCH "`scratch'" %token K_SPACE "`space'" +%token K_STACK "`stack'" +%token K_X87_ARITH "`x87_arith'" +%token K_X87_ARITH_REVERSIBLE "`x87_arith_reversible'" %token K_INST_TYPE "`%inst_type'" +%token K_REG_CLASS "`%reg_class'" +%token K_LREG_CLASS "`%lreg_class'" /* deperecated keywords */ %token K_MANUAL "`manual'" %token K_MORE_SPACE "`more_space'" -%token K_SPILL_BEFORE "`spill_before'" /* * Define the yylval types of the various non-terminals. @@ -1736,12 +1648,12 @@ static void gensel_output_supported(void) %type CODE_BLOCK %type IDENTIFIER LITERAL %type IfClause IdentifierList Literal -%type OptionTag InputTag RegTag LRegTag RegFlag LocalTag LocalFlag +%type OptionTag InputTag DestFlag RegFlag %type Clauses Clause -%type Options OptionList Pattern Pattern2 -%type