From: Aleksey Demakov Date: Tue, 10 Jan 2006 21:24:42 +0000 (+0000) Subject: added jit_insn_jump_table X-Git-Tag: r.0.0.6~5 X-Git-Url: https://git.unchartedbackwaters.co.uk/w/?a=commitdiff_plain;h=045b16fa82cd0fd4950525b70eea2cf1c26f95a3;p=francis%2Flibjit.git added jit_insn_jump_table --- diff --git a/ChangeLog b/ChangeLog index 14b39dc..002eb4c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -5,6 +5,10 @@ * jit/jit-internal.h, jit/jit-function.c, jiy/jit-rules-x86.c: add fixup_absolute_list field to _jit_block struct for fixing up absolute address references to a block. + * include/jit/jit-opcode.h (JIT_OP_JUMP_TABLE), + * jit/jit-rules-x86.sel (JIT_OP_JUMP_TABLE), + * include/jit/jit-insn.h, jit/jit-insn.c (jit_insn_jump_table): + add new opcode. 2006-01-08 Aleksey Demakov diff --git a/include/jit/jit-insn.h b/include/jit/jit-insn.h index f39ce8f..7b1933c 100644 --- a/include/jit/jit-insn.h +++ b/include/jit/jit-insn.h @@ -209,6 +209,9 @@ int jit_insn_branch_if (jit_function_t func, jit_value_t value, jit_label_t *label) JIT_NOTHROW; int jit_insn_branch_if_not (jit_function_t func, jit_value_t value, jit_label_t *label) JIT_NOTHROW; +int jit_insn_jump_table + (jit_function_t func, jit_value_t value, + jit_label_t *labels, unsigned int num_labels) JIT_NOTHROW; jit_value_t jit_insn_address_of (jit_function_t func, jit_value_t value1) JIT_NOTHROW; jit_value_t jit_insn_address_of_label diff --git a/include/jit/jit-opcode.h b/include/jit/jit-opcode.h index 438c6cd..7006ead 100644 --- a/include/jit/jit-opcode.h +++ b/include/jit/jit-opcode.h @@ -520,10 +520,15 @@ extern "C" { #define JIT_OP_MARK_OFFSET 0x01A3 #define JIT_OP_MARK_BREAKPOINT 0x01A4 +/* + * Switch statement support. + */ +#define JIT_OP_JUMP_TABLE 0x01A5 + /* * The number of opcodes in the above list. */ -#define JIT_OP_NUM_OPCODES 0x01A5 +#define JIT_OP_NUM_OPCODES 0x01A6 /* * Opcode information. diff --git a/jit/jit-insn.c b/jit/jit-insn.c index fa4779c..13167fa 100644 --- a/jit/jit-insn.c +++ b/jit/jit-insn.c @@ -3940,6 +3940,106 @@ add_block: return jit_insn_new_block(func); } +/*@ + * @deftypefun jit_insn_jump_table(jit_function_t func, jit_value_t value, jit_label_t *labels, unsigned int num_labels) + * + * @end deftypefun +@*/ +int jit_insn_jump_table + (jit_function_t func, jit_value_t value, + jit_label_t *labels, unsigned int num_labels) +{ + jit_insn_t insn; + unsigned int index; + jit_label_t *new_labels; + jit_value_t value_labels; + jit_value_t value_num_labels; + + /* Bail out if the parameters are invalid */ + if(!value || !labels || !num_labels) + { + return 0; + } + + /* Ensure that we have a function builder */ + if(!_jit_function_ensure_builder(func)) + { + return 0; + } + + /* Flush any stack pops that were deferred previously */ + if(!jit_insn_flush_defer_pop(func, 0)) + { + return 0; + } + + /* Allocate new label identifiers, if necessary */ + for(index = 0; index < num_labels; index++) + { + if(labels[index] == jit_label_undefined) + { + labels[index] = (func->builder->next_label)++; + } + } + + /* If the condition is constant, then convert it into either + an unconditional branch or a fall-through, as appropriate */ + if(jit_value_is_constant(value)) + { + index = jit_value_get_nint_constant(value); + if(index < num_labels && index >= 0) + { + return jit_insn_branch(func, &labels[index]); + } + else + { + return 1; + } + } + + new_labels = jit_malloc(num_labels * sizeof(jit_label_t)); + if(!new_labels) + { + return 0; + } + for(index = 0; index < num_labels; index++) + { + new_labels[index] = labels[index]; + } + + value_labels = jit_value_create_nint_constant(func, jit_type_void_ptr, (jit_nint) new_labels); + if(!value_labels) + { + jit_free(new_labels); + return 0; + } + value_labels->free_address = 1; + + value_num_labels = jit_value_create_nint_constant(func, jit_type_uint, num_labels); + if(!value_num_labels) + { + _jit_value_free(value_labels); + return 0; + } + + /* Add a new branch instruction */ + insn = _jit_block_add_insn(func->builder->current_block); + if(!insn) + { + return 0; + } + jit_value_ref(func, value); + + insn->opcode = JIT_OP_JUMP_TABLE; + insn->flags = JIT_INSN_DEST_IS_VALUE; + insn->dest = value; + insn->value1 = value_labels; + insn->value2 = value_num_labels; + + /* Add a new block for the fall-through case */ + return jit_insn_new_block(func); +} + /*@ * @deftypefun jit_value_t jit_insn_address_of (jit_function_t func, jit_value_t value1) * Get the address of a value into a new temporary. diff --git a/jit/jit-rules-x86.sel b/jit/jit-rules-x86.sel index a8893e9..25c0dc6 100644 --- a/jit/jit-rules-x86.sel +++ b/jit/jit-rules-x86.sel @@ -3125,6 +3125,9 @@ JIT_OP_MEMCPY: manual reg3 = _jit_regs_load_value (gen, insn->value2, 0, (insn->flags & (JIT_INSN_VALUE2_NEXT_USE | JIT_INSN_VALUE2_LIVE))); + + /* A function call may destroy EAX,EBX,ECX,EDX registers. */ + /* TODO: do not spill ESI and EDI. */ _jit_regs_spill_all(gen); inst = gen->posn.ptr; @@ -3374,3 +3377,69 @@ JIT_OP_ALLOCA: unary x86_mov_reg_reg(inst, $1, X86_ESP, 4); gen->stack_changed = 1; } + +JIT_OP_JUMP_TABLE: manual + [] -> { + unsigned char *inst; + unsigned char *patch_jump_table; + unsigned char *patch_fall_through; + int reg; + int index; + jit_label_t *labels; + jit_nint num_labels; + jit_block_t block; + int address; + + reg = _jit_regs_load_value + (gen, insn->dest, 0, + (insn->flags & (JIT_INSN_DEST_NEXT_USE | JIT_INSN_DEST_LIVE))); + _jit_regs_spill_all(gen); + + labels = (jit_label_t *) insn->value1->address; + num_labels = insn->value2->address; + + inst = gen->posn.ptr; + if(!jit_cache_check_for_n(&(gen->posn), 32 + sizeof(void) * num_labels)) + { + jit_cache_mark_full(&(gen->posn)); + return; + } + + x86_alu_reg_imm(inst, X86_CMP, reg, num_labels); + patch_fall_through = inst; + x86_branch32(inst, X86_CC_GE, 0, 1); + + patch_jump_table = inst; + x86_jump_memindex(inst, X86_NOBASEREG, 0, reg, 2); + while(((jit_nint) inst & (sizeof(void*) - 1)) != 0) + { + x86_nop(inst); + } + + // displacement goes after opcode. ModR/M, and SIB bytes + *((void **)(patch_jump_table + 3)) = inst; + + for(index = 0; index < num_labels; index++) + { + block = jit_block_from_label(func, labels[index]); + if(!block) + { + return; + } + + if(block->address) + { + x86_imm_emit32(inst, address); + } + else + { + /* Output a placeholder and record on the block's fixup list */ + x86_imm_emit32(inst, (int)(block->fixup_absolute_list)); + block->fixup_absolute_list = (void *)(inst - 4); + } + } + + x86_patch(patch_fall_through, inst); + + gen->posn.ptr = inst; + }