From: Rhys Weatherley Date: Thu, 27 May 2004 04:36:30 +0000 (+0000) Subject: Relative loads and stores for x86. X-Git-Tag: r.0.0.4~75 X-Git-Url: https://git.unchartedbackwaters.co.uk/w/?a=commitdiff_plain;h=d7687d0107adfed035c7167856684deb0c2fd960;p=francis%2Flibjit.git Relative loads and stores for x86. --- diff --git a/ChangeLog b/ChangeLog index 5a8147e..9de459f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -10,6 +10,9 @@ "nfloat" as identical on platforms whose "long double" type is the same as "double". + * jit/jit-rules-x86.c, jit/jit-rules-x86.sel, tools/gen-sel-parser.y, + tools/gen-sel-scanner.l: relative loads and stores for x86. + 2004-05-26 Rhys Weatherley * jit/jit-insn.c, jit/jit-rules-x86.c, jit/jit-rules-x86.sel, diff --git a/jit/jit-rules-x86.c b/jit/jit-rules-x86.c index 81d549c..62cb530 100644 --- a/jit/jit-rules-x86.c +++ b/jit/jit-rules-x86.c @@ -1326,6 +1326,80 @@ static unsigned char *jump_to_epilog return inst; } +/* + * Get a register pair for temporary operations on "long" values. + */ +static void get_reg_pair(jit_gencode_t gen, int not_this1, int not_this2, + int not_this3, int *reg, int *reg2) +{ + int index; + for(index = 0; index < 8; ++index) + { + if((_jit_reg_info[index].flags & JIT_REG_WORD) == 0 || + jit_reg_is_used(gen->permanent, index)) + { + continue; + } + if(index != not_this1 && index != not_this2 && + index != not_this3) + { + break; + } + } + *reg = index; + _jit_regs_want_reg(gen, index, 0); + for(; index < 8; ++index) + { + if((_jit_reg_info[index].flags & JIT_REG_WORD) == 0 || + jit_reg_is_used(gen->permanent, index)) + { + continue; + } + if(index != not_this1 && index != not_this2 && + index != not_this3 && index != *reg) + { + break; + } + } + if(index >= 8) + { + *reg2 = -1; + } + else + { + *reg2 = index; + _jit_regs_want_reg(gen, index, 0); + } +} + +/* + * Store a byte value to a membase address. + */ +static unsigned char *mov_membase_reg_byte + (unsigned char *inst, int basereg, int offset, int srcreg) +{ + if(srcreg == X86_EAX || srcreg == X86_EBX || + srcreg == X86_ECX || srcreg == X86_EDX) + { + x86_mov_membase_reg(inst, basereg, offset, srcreg, 1); + } + else if(basereg != X86_EAX) + { + x86_push_reg(inst, X86_EAX); + x86_mov_reg_reg(inst, X86_EAX, srcreg, 4); + x86_mov_membase_reg(inst, basereg, offset, X86_EAX, 1); + x86_pop_reg(inst, X86_EAX); + } + else + { + x86_push_reg(inst, X86_EDX); + x86_mov_reg_reg(inst, X86_EDX, srcreg, 4); + x86_mov_membase_reg(inst, basereg, offset, X86_EDX, 1); + x86_pop_reg(inst, X86_EDX); + } + return inst; +} + void _jit_gen_insn(jit_gencode_t gen, jit_function_t func, jit_block_t block, jit_insn_t insn) { diff --git a/jit/jit-rules-x86.sel b/jit/jit-rules-x86.sel index ddd8eab..fa8fc6f 100644 --- a/jit/jit-rules-x86.sel +++ b/jit/jit-rules-x86.sel @@ -911,3 +911,440 @@ JIT_OP_FLUSH_SMALL_STRUCT: break; } } + +/* + * Pointer-relative loads and stores. + */ + +JIT_OP_LOAD_RELATIVE_SBYTE: unary + [reg] -> { + x86_widen_membase(inst, $1, $1, insn->value2->address, 1, 0); + } + +JIT_OP_LOAD_RELATIVE_UBYTE: unary + [reg] -> { + x86_widen_membase(inst, $1, $1, insn->value2->address, 0, 0); + } + +JIT_OP_LOAD_RELATIVE_SHORT: unary + [reg] -> { + x86_widen_membase(inst, $1, $1, insn->value2->address, 1, 1); + } + +JIT_OP_LOAD_RELATIVE_USHORT: unary + [reg] -> { + x86_widen_membase(inst, $1, $1, insn->value2->address, 0, 1); + } + +JIT_OP_LOAD_RELATIVE_INT: unary + [reg] -> { + x86_mov_reg_membase(inst, $1, $1, insn->value2->address, 4); + } + +JIT_OP_LOAD_RELATIVE_LONG: 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))); + int reg2, reg3; + int frame_offset; + _jit_gen_fix_value(insn->dest); + get_reg_pair(gen, reg, -1, -1, ®2, ®3); + reg = _jit_reg_info[reg].cpu_reg; + reg2 = _jit_reg_info[reg2].cpu_reg; + reg3 = _jit_reg_info[reg3].cpu_reg; + frame_offset = insn->dest->frame_offset; + inst = gen->posn.ptr; + if(!jit_cache_check_for_n(&(gen->posn), 32)) + { + jit_cache_mark_full(&(gen->posn)); + return; + } + x86_mov_reg_membase(inst, reg2, reg, insn->value2->address, 4); + x86_mov_reg_membase(inst, reg3, reg, insn->value2->address + 4, 4); + x86_mov_membase_reg(inst, X86_EBP, frame_offset, reg2, 4); + x86_mov_membase_reg(inst, X86_EBP, frame_offset + 4, reg3, 4); + insn->dest->in_frame = 1; + 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_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_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_STRUCT: manual + [] -> { + /* TODO */ + } + +JIT_OP_STORE_RELATIVE_BYTE: manual + [] -> { + unsigned char *inst; + int reg = _jit_regs_load_value + (gen, insn->dest, 0, + (insn->flags & (JIT_INSN_DEST_NEXT_USE | + JIT_INSN_DEST_LIVE))); + if(!(insn->value1->is_constant)) + { + int reg2 = _jit_regs_load_value + (gen, insn->value1, 0, + (insn->flags & (JIT_INSN_VALUE1_NEXT_USE | + JIT_INSN_VALUE1_LIVE))); + inst = gen->posn.ptr; + if(!jit_cache_check_for_n(&(gen->posn), 32)) + { + jit_cache_mark_full(&(gen->posn)); + return; + } + reg = _jit_reg_info[reg].cpu_reg; + reg2 = _jit_reg_info[reg2].cpu_reg; + inst = mov_membase_reg_byte + (inst, reg, insn->value2->address, reg2); + gen->posn.ptr = inst; + } + else + { + inst = gen->posn.ptr; + if(!jit_cache_check_for_n(&(gen->posn), 32)) + { + jit_cache_mark_full(&(gen->posn)); + return; + } + reg = _jit_reg_info[reg].cpu_reg; + x86_mov_membase_imm(inst, reg, insn->value2->address, + insn->value1->address, 1); + gen->posn.ptr = inst; + } + } + +JIT_OP_STORE_RELATIVE_SHORT: manual + [] -> { + unsigned char *inst; + int reg = _jit_regs_load_value + (gen, insn->dest, 0, + (insn->flags & (JIT_INSN_DEST_NEXT_USE | + JIT_INSN_DEST_LIVE))); + if(!(insn->value1->is_constant)) + { + int reg2 = _jit_regs_load_value + (gen, insn->value1, 0, + (insn->flags & (JIT_INSN_VALUE1_NEXT_USE | + JIT_INSN_VALUE1_LIVE))); + inst = gen->posn.ptr; + if(!jit_cache_check_for_n(&(gen->posn), 32)) + { + jit_cache_mark_full(&(gen->posn)); + return; + } + reg = _jit_reg_info[reg].cpu_reg; + reg2 = _jit_reg_info[reg2].cpu_reg; + x86_mov_membase_reg(inst, reg, insn->value2->address, reg2, 2); + gen->posn.ptr = inst; + } + else + { + inst = gen->posn.ptr; + if(!jit_cache_check_for_n(&(gen->posn), 32)) + { + jit_cache_mark_full(&(gen->posn)); + return; + } + reg = _jit_reg_info[reg].cpu_reg; + x86_mov_membase_imm(inst, reg, insn->value2->address, + insn->value1->address, 2); + gen->posn.ptr = inst; + } + } + +JIT_OP_STORE_RELATIVE_INT: manual + [] -> { + unsigned char *inst; + int reg = _jit_regs_load_value + (gen, insn->dest, 0, + (insn->flags & (JIT_INSN_DEST_NEXT_USE | + JIT_INSN_DEST_LIVE))); + if(!(insn->value1->is_constant)) + { + int reg2 = _jit_regs_load_value + (gen, insn->value1, 0, + (insn->flags & (JIT_INSN_VALUE1_NEXT_USE | + JIT_INSN_VALUE1_LIVE))); + inst = gen->posn.ptr; + if(!jit_cache_check_for_n(&(gen->posn), 32)) + { + jit_cache_mark_full(&(gen->posn)); + return; + } + reg = _jit_reg_info[reg].cpu_reg; + reg2 = _jit_reg_info[reg2].cpu_reg; + x86_mov_membase_reg(inst, reg, insn->value2->address, reg2, 4); + gen->posn.ptr = inst; + } + else + { + inst = gen->posn.ptr; + if(!jit_cache_check_for_n(&(gen->posn), 32)) + { + jit_cache_mark_full(&(gen->posn)); + return; + } + reg = _jit_reg_info[reg].cpu_reg; + x86_mov_membase_imm(inst, reg, insn->value2->address, + insn->value1->address, 4); + gen->posn.ptr = inst; + } + } + +JIT_OP_STORE_RELATIVE_LONG: manual + [] -> { + unsigned char *inst; + int reg = _jit_regs_load_value + (gen, insn->dest, 0, + (insn->flags & (JIT_INSN_DEST_NEXT_USE | + JIT_INSN_DEST_LIVE))); + int reg2, reg3; + int frame_offset; + if(!(insn->value1->is_constant)) + { + get_reg_pair(gen, reg, -1, -1, ®2, ®3); + _jit_gen_fix_value(insn->value1); + 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; + reg3 = _jit_reg_info[reg3].cpu_reg; + frame_offset = insn->value1->frame_offset; + x86_mov_reg_membase(inst, reg2, X86_EBP, frame_offset, 4); + x86_mov_reg_membase(inst, reg3, X86_EBP, frame_offset + 4, 4); + x86_mov_membase_reg(inst, reg, insn->value2->address, reg2, 4); + x86_mov_membase_reg(inst, reg, insn->value2->address + 4, reg3, 4); + gen->posn.ptr = inst; + } + else + { + jit_long const_value = jit_value_get_long_constant(insn->value1); + 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_mov_membase_imm + (inst, reg, insn->value2->address, + (jit_int)(const_value & jit_max_uint), 4); + x86_mov_membase_imm + (inst, reg, insn->value2->address, + (jit_int)((const_value >> 32) & jit_max_uint), 4); + gen->posn.ptr = inst; + } + } + +JIT_OP_STORE_RELATIVE_FLOAT32: manual + [] -> { + unsigned char *inst; + int reg = _jit_regs_load_value + (gen, insn->dest, 0, + (insn->flags & (JIT_INSN_DEST_NEXT_USE | + JIT_INSN_DEST_LIVE))); + if(!(insn->value1->is_constant)) + { + _jit_regs_load_to_top + (gen, insn->value1, + (insn->flags & (JIT_INSN_VALUE1_NEXT_USE | + JIT_INSN_VALUE1_LIVE)), 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_fst_membase(inst, reg, insn->value2->address, 0, 1); + gen->posn.ptr = inst; + } + else + { + inst = gen->posn.ptr; + if(!jit_cache_check_for_n(&(gen->posn), 32)) + { + jit_cache_mark_full(&(gen->posn)); + return; + } + reg = _jit_reg_info[reg].cpu_reg; + x86_mov_membase_imm(inst, reg, insn->value2->address, + *((int *)(insn->value1->address)), 4); + gen->posn.ptr = inst; + } + } + +JIT_OP_STORE_RELATIVE_FLOAT64: manual + [] -> { + unsigned char *inst; + int reg = _jit_regs_load_value + (gen, insn->dest, 0, + (insn->flags & (JIT_INSN_DEST_NEXT_USE | + JIT_INSN_DEST_LIVE))); + if(!(insn->value1->is_constant)) + { + _jit_regs_load_to_top + (gen, insn->value1, + (insn->flags & (JIT_INSN_VALUE1_NEXT_USE | + JIT_INSN_VALUE1_LIVE)), 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_fst_membase(inst, reg, insn->value2->address, 1, 1); + gen->posn.ptr = inst; + } + else + { + inst = gen->posn.ptr; + if(!jit_cache_check_for_n(&(gen->posn), 32)) + { + jit_cache_mark_full(&(gen->posn)); + return; + } + reg = _jit_reg_info[reg].cpu_reg; + x86_mov_membase_imm(inst, reg, insn->value2->address, + ((int *)(insn->value1->address))[0], 4); + x86_mov_membase_imm(inst, reg, insn->value2->address + 4, + ((int *)(insn->value1->address))[1], 4); + gen->posn.ptr = inst; + } + } + +JIT_OP_STORE_RELATIVE_NFLOAT: manual + [] -> { + unsigned char *inst; + int reg = _jit_regs_load_value + (gen, insn->dest, 0, + (insn->flags & (JIT_INSN_DEST_NEXT_USE | + JIT_INSN_DEST_LIVE))); + if(!(insn->value1->is_constant)) + { + _jit_regs_load_to_top + (gen, insn->value1, + (insn->flags & (JIT_INSN_VALUE1_NEXT_USE | + JIT_INSN_VALUE1_LIVE)), 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_fst80_membase(inst, reg, insn->value2->address); + } + else + { + x86_fst_membase(inst, reg, insn->value2->address, 1, 1); + } + gen->posn.ptr = inst; + } + else + { + inst = gen->posn.ptr; + if(!jit_cache_check_for_n(&(gen->posn), 32)) + { + jit_cache_mark_full(&(gen->posn)); + return; + } + reg = _jit_reg_info[reg].cpu_reg; + x86_mov_membase_imm(inst, reg, insn->value2->address, + ((int *)(insn->value1->address))[0], 4); + x86_mov_membase_imm(inst, reg, insn->value2->address + 4, + ((int *)(insn->value1->address))[1], 4); + if(sizeof(jit_nfloat) != sizeof(jit_float64)) + { + x86_mov_membase_imm(inst, reg, insn->value2->address + 8, + ((int *)(insn->value1->address))[2], 4); + } + gen->posn.ptr = inst; + } + } + +JIT_OP_STORE_RELATIVE_STRUCT: manual + [] -> { + /* TODO */ + } + +JIT_OP_ADD_RELATIVE: unary + [reg] -> { + if(insn->value2->address != 0) + { + x86_alu_reg_imm(inst, X86_ADD, $1, insn->value2->address); + } + } diff --git a/tools/gen-sel-parser.y b/tools/gen-sel-parser.y index 368e102..b6ac6fe 100644 --- a/tools/gen-sel-parser.y +++ b/tools/gen-sel-parser.y @@ -76,6 +76,7 @@ static int gensel_first_stack_reg = 8; /* st0 under x86 */ #define GENSEL_OPT_UNARY_BRANCH 0x0020 #define GENSEL_OPT_BINARY_BRANCH 0x0040 #define GENSEL_OPT_ONLY 0x0080 +#define GENSEL_OPT_MANUAL 0x0100 /* * Pattern values. @@ -194,22 +195,13 @@ static void gensel_declare_regs(gensel_clause_t clauses, int options) } /* - * Output a single clause for a rule. + * Output the code within a clause. */ -static void gensel_output_clause(gensel_clause_t clause) +static void gensel_output_clause_code(gensel_clause_t clause) { char *code; int index; - /* Cache the instruction pointer into "inst" */ - printf("\t\tinst = (%s)(gen->posn.ptr);\n", gensel_inst_type); - printf("\t\tif(!jit_cache_check_for_n(&(gen->posn), %d))\n", - gensel_reserve_space); - printf("\t\t{\n"); - printf("\t\t\tjit_cache_mark_full(&(gen->posn));\n"); - printf("\t\t\treturn;\n"); - printf("\t\t}\n"); - /* Output the line number information from the original file */ printf("#line %ld \"%s\"\n", clause->linenum, clause->filename); @@ -268,6 +260,24 @@ static void gensel_output_clause(gensel_clause_t clause) } } printf("\n"); +} + +/* + * Output a single clause for a rule. + */ +static void gensel_output_clause(gensel_clause_t clause) +{ + /* Cache the instruction pointer into "inst" */ + printf("\t\tinst = (%s)(gen->posn.ptr);\n", gensel_inst_type); + printf("\t\tif(!jit_cache_check_for_n(&(gen->posn), %d))\n", + gensel_reserve_space); + printf("\t\t{\n"); + printf("\t\t\tjit_cache_mark_full(&(gen->posn));\n"); + printf("\t\t\treturn;\n"); + printf("\t\t}\n"); + + /* Output the clause code */ + gensel_output_clause_code(clause); /* Copy "inst" back into the generation context */ printf("\t\tgen->posn.ptr = (unsigned char *)inst;\n"); @@ -295,6 +305,13 @@ static void gensel_output_clauses(gensel_clause_t clauses, int options) int first, index; int check_index; + /* If the clause is manual, then output it as-is */ + if((options & GENSEL_OPT_MANUAL) != 0) + { + gensel_output_clause_code(clauses); + return; + } + /* Determine the location of this instruction's arguments */ if((options & GENSEL_OPT_TERNARY) != 0) { @@ -656,6 +673,7 @@ static void gensel_output_supported(void) %token K_TERNARY "`ternary'" %token K_STACK "`stack'" %token K_ONLY "`only'" +%token K_MANUAL "`manual'" %token K_INST_TYPE "`%inst_type'" /* @@ -685,7 +703,10 @@ Rules Rule : IDENTIFIER ':' Options Clauses { printf("case %s:\n{\n", $1); - printf("\t%s inst;\n", gensel_inst_type); + if(($3 & GENSEL_OPT_MANUAL) == 0) + { + printf("\t%s inst;\n", gensel_inst_type); + } gensel_declare_regs($4.head, $3); if(($3 & GENSEL_OPT_SPILL_BEFORE) != 0) { @@ -733,6 +754,7 @@ Option | K_TERNARY { $$ = GENSEL_OPT_TERNARY; } | K_STACK { $$ = GENSEL_OPT_STACK; } | K_ONLY { $$ = GENSEL_OPT_ONLY; } + | K_MANUAL { $$ = GENSEL_OPT_MANUAL; } ; Clauses diff --git a/tools/gen-sel-scanner.l b/tools/gen-sel-scanner.l index 69a7df5..51a7934 100644 --- a/tools/gen-sel-scanner.l +++ b/tools/gen-sel-scanner.l @@ -100,6 +100,7 @@ WHITE [ \t\v\r\f] "binary_branch" { RETURNTOK(K_BINARY_BRANCH); } "unary_note" { RETURNTOK(K_UNARY_BRANCH); } "binary_note" { RETURNTOK(K_BINARY_BRANCH); } +"manual" { RETURNTOK(K_MANUAL); } "stack" { RETURNTOK(K_STACK); } "only" { RETURNTOK(K_ONLY); } "%inst_type" { RETURNTOK(K_INST_TYPE); }