]> git.unchartedbackwaters.co.uk Git - francis/libjit.git/commitdiff
added jit_insn_jump_table
authorAleksey Demakov <ademakov@gmail.com>
Tue, 10 Jan 2006 21:24:42 +0000 (21:24 +0000)
committerAleksey Demakov <ademakov@gmail.com>
Tue, 10 Jan 2006 21:24:42 +0000 (21:24 +0000)
ChangeLog
include/jit/jit-insn.h
include/jit/jit-opcode.h
jit/jit-insn.c
jit/jit-rules-x86.sel

index 14b39dceb19d8b6cc5538f1b31796dc25eedd078..002eb4c8861c1cd4cc1b31ffae6d8f96e479ab8f 100644 (file)
--- 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  <ademakov@gmail.com>
 
index f39ce8f6fb1e640a418367425229b9e2e67a511f..7b1933c9908b657a04ae1792ae07d4df3e9d125a 100644 (file)
@@ -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
index 438c6cd607f3a806efead348099554023404e1c7..7006eadec45108a078941ae80d8b5469d604b4d2 100644 (file)
@@ -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.
index fa4779c4bc11aa74fdca52cef872055fb0ca3dde..13167faa2f85b007f7f88d922a5cf67caff51f96 100644 (file)
@@ -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.
index a8893e984e9bed8f7e8ff9389fca77d39bf1725c..25c0dc63a1bef1b6b2b09700075dc20b823aa019 100644 (file)
@@ -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;
+       }