]> git.unchartedbackwaters.co.uk Git - francis/libjit.git/commitdiff
Add array access instructions.
authorRhys Weatherley <rweather@southern-storm.com.au>
Sat, 1 May 2004 07:25:52 +0000 (07:25 +0000)
committerRhys Weatherley <rweather@southern-storm.com.au>
Sat, 1 May 2004 07:25:52 +0000 (07:25 +0000)
ChangeLog
include/jit/jit-insn.h
include/jit/jit-opcode.h
include/jit/jit-plus.h
jit/jit-insn.c
jit/jit-interp.cpp
jit/jit-opcode.c
jit/jit-reg-alloc.c
jit/jit-reg-alloc.h
jit/jit-rules-interp.c
jitplus/jit-plus-function.cpp

index 4a28a9a60e63fa130bc55d90c19409f3d13b9dee..ef747d842a664e24e74c23ab0a611a1c89283166 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
        * jit/jit-rules-x86.c: implement x86 code generation for some of
        the basic operators.
 
+       * include/jit/jit-insn.h, include/jit/jit-opcode.h,
+       include/jit/jit-plus.h, jit/jit-insn.c, jit/jit-interp.cpp,
+       jit/jit-opcode.c, jit/jit-reg-alloc.c, jit/jit-reg-alloc.h,
+       jit/jit-rules-interp.c, jitplus/jit-plus-function.cpp:
+       add array access instructions.
+
 2004-04-30  Rhys Weatherley  <rweather@southern-storm.com.au>
 
        * include/jit/jit-function.h, include/jit/jit-insn.h,
index b0f9d3557a1b5a70a2d4a032494584aa6e87f447..d5b1a8438cabb63642cf02f81b5700c81de3f068 100644 (file)
@@ -83,6 +83,15 @@ int jit_insn_store_relative
         jit_nint offset, jit_value_t value) JIT_NOTHROW;
 jit_value_t jit_insn_add_relative
        (jit_function_t func, jit_value_t value, jit_nint offset) JIT_NOTHROW;
+jit_value_t jit_insn_load_elem
+       (jit_function_t func, jit_value_t base_addr,
+        jit_value_t index, jit_type_t elem_type) JIT_NOTHROW;
+jit_value_t jit_insn_load_elem_address
+       (jit_function_t func, jit_value_t base_addr,
+        jit_value_t index, jit_type_t elem_type) JIT_NOTHROW;
+int jit_insn_store_elem
+       (jit_function_t func, jit_value_t base_addr,
+        jit_value_t index, jit_value_t value) JIT_NOTHROW;
 int jit_insn_check_null(jit_function_t func, jit_value_t value) JIT_NOTHROW;
 
 jit_value_t jit_insn_add
@@ -257,6 +266,16 @@ jit_value_t jit_insn_call_filter
        (jit_function_t func, jit_label_t *label,
         jit_value_t value, jit_type_t type);
 
+int jit_insn_memcpy
+       (jit_function_t func, jit_value_t dest,
+        jit_value_t src, jit_value_t size) JIT_NOTHROW;
+int jit_insn_memmove
+       (jit_function_t func, jit_value_t dest,
+        jit_value_t src, jit_value_t size) JIT_NOTHROW;
+int jit_insn_memset
+       (jit_function_t func, jit_value_t dest,
+        jit_value_t value, jit_value_t size) JIT_NOTHROW;
+
 void jit_insn_iter_init(jit_insn_iter_t *iter, jit_block_t block) JIT_NOTHROW;
 void jit_insn_iter_init_last
        (jit_insn_iter_t *iter, jit_block_t block) JIT_NOTHROW;
index fc7e7d1d32cacce95f86a537cca2fc7608febf86..2b08ecd9408cf80cb84bd6d493650c640eeda51b 100644 (file)
@@ -470,10 +470,39 @@ extern    "C" {
 #define        JIT_OP_STORE_RELATIVE_STRUCT            0x0181
 #define        JIT_OP_ADD_RELATIVE                                     0x0182
 
+/*
+ * Array element loads and stores.
+ */
+#define        JIT_OP_LOAD_ELEMENT_SBYTE                       0x0183
+#define        JIT_OP_LOAD_ELEMENT_UBYTE                       0x0184
+#define        JIT_OP_LOAD_ELEMENT_SHORT                       0x0185
+#define        JIT_OP_LOAD_ELEMENT_USHORT                      0x0186
+#define        JIT_OP_LOAD_ELEMENT_INT                         0x0187
+#define        JIT_OP_LOAD_ELEMENT_UINT                        0x0188
+#define        JIT_OP_LOAD_ELEMENT_LONG                        0x0189
+#define        JIT_OP_LOAD_ELEMENT_ULONG                       0x018A
+#define        JIT_OP_LOAD_ELEMENT_FLOAT32                     0x018B
+#define        JIT_OP_LOAD_ELEMENT_FLOAT64                     0x018C
+#define        JIT_OP_LOAD_ELEMENT_NFLOAT                      0x018D
+#define        JIT_OP_STORE_ELEMENT_BYTE                       0x018E
+#define        JIT_OP_STORE_ELEMENT_SHORT                      0x018F
+#define        JIT_OP_STORE_ELEMENT_INT                        0x0190
+#define        JIT_OP_STORE_ELEMENT_LONG                       0x0191
+#define        JIT_OP_STORE_ELEMENT_FLOAT32            0x0192
+#define        JIT_OP_STORE_ELEMENT_FLOAT64            0x0193
+#define        JIT_OP_STORE_ELEMENT_NFLOAT                     0x0194
+
+/*
+ * Block operations.
+ */
+#define        JIT_OP_MEMCPY                                           0x0195
+#define        JIT_OP_MEMMOVE                                          0x0196
+#define        JIT_OP_MEMSET                                           0x0197
+
 /*
  * The number of opcodes in the above list.
  */
-#define        JIT_OP_NUM_OPCODES                                      0x0183
+#define        JIT_OP_NUM_OPCODES                                      0x0198
 
 /*
  * Opcode information.
index 920600e335d4167ab67413089a613bd5d941cf9d..051ef659221117d51e0a39350c9ea9b65dde195f 100644 (file)
@@ -215,6 +215,15 @@ public:
        void insn_store_relative
                (const jit_value& dest, jit_nint offset, const jit_value& value);
        jit_value insn_add_relative(const jit_value& value, jit_nint offset);
+       jit_value insn_load_elem
+               (const jit_value& base_addr, const jit_value& index,
+                jit_type_t elem_type);
+       jit_value insn_load_elem_address
+               (const jit_value& base_addr, const jit_value& index,
+                jit_type_t elem_type);
+       void insn_store_elem
+               (const jit_value& base_addr, const jit_value& index,
+                const jit_value& value);
        void insn_check_null(const jit_value& value);
        jit_value insn_add(const jit_value& value1, const jit_value& value2);
        jit_value insn_add_ovf(const jit_value& value1, const jit_value& value2);
@@ -299,6 +308,12 @@ public:
        void insn_default_return();
        void insn_throw(const jit_value& value);
        jit_value insn_get_call_stack();
+       void insn_memcpy
+               (const jit_value& dest, const jit_value& src, const jit_value& size);
+       void insn_memmove
+               (const jit_value& dest, const jit_value& src, const jit_value& size);
+       void insn_memset
+               (const jit_value& dest, const jit_value& value, const jit_value& size);
 
 private:
        jit_function_t func;
index efafa90c240ed9a4a11c987391c7c387bacd882d..6de9057a6724f9d98f5f0aaa4ae021e4c0cf2477 100644 (file)
@@ -336,6 +336,38 @@ static jit_value_t apply_binary
        return dest;
 }
 
+/*
+ * Apply a ternary operator.
+ */
+static int apply_ternary
+               (jit_function_t func, int oper, jit_value_t value1,
+                jit_value_t value2, jit_value_t value3)
+{
+       jit_insn_t insn;
+       if(!value1 || !value2 || !value3)
+       {
+               return 0;
+       }
+       if(!_jit_function_ensure_builder(func))
+       {
+               return 0;
+       }
+       insn = _jit_block_add_insn(func->builder->current_block);
+       if(!insn)
+       {
+               return 0;
+       }
+       jit_value_ref(func, value1);
+       jit_value_ref(func, value2);
+       jit_value_ref(func, value3);
+       insn->opcode = (short)oper;
+       insn->flags = JIT_INSN_DEST_IS_VALUE;
+       insn->dest = value1;
+       insn->value1 = value2;
+       insn->value2 = value3;
+       return 1;
+}
+
 /*
  * Create a note instruction, which doesn't have a result.
  */
@@ -1623,6 +1655,127 @@ jit_value_t jit_insn_add_relative
        }
 }
 
+/*@
+ * @deftypefun jit_value_t jit_insn_load_elem (jit_function_t func, jit_value_t base_addr, jit_value_t index, jit_type_t elem_type)
+ * Load an element of type @code{elem_type} from position @code{index} within
+ * the array starting at @code{base_addr}.  The effective address of the
+ * array element is @code{base_addr + index * sizeof(elem_type)}.
+ * @end deftypefun
+@*/
+jit_value_t jit_insn_load_elem
+       (jit_function_t func, jit_value_t base_addr,
+        jit_value_t index, jit_type_t elem_type)
+{
+       jit_nint size;
+       int opcode;
+
+       /* Get the size of the element that we are fetching */
+       size = (jit_nint)(jit_type_get_size(elem_type));
+
+       /* Convert the index into a native integer */
+       index = jit_insn_convert(func, index, jit_type_nint, 0);
+       if(!index)
+       {
+               return 0;
+       }
+
+       /* If the index is constant, then turn this into a relative load */
+       if(jit_value_is_constant(index))
+       {
+               return jit_insn_load_relative
+                       (func, base_addr,
+                        jit_value_get_nint_constant(index) * size, elem_type);
+       }
+
+       /* See if we can use a special-case instruction */
+       opcode = _jit_load_opcode(JIT_OP_LOAD_ELEMENT_SBYTE, elem_type, 0, 0);
+       if(opcode != 0 && opcode != (JIT_OP_LOAD_ELEMENT_SBYTE + 9))
+       {
+               return apply_binary(func, opcode, base_addr, index, elem_type);
+       }
+
+       /* Calculate the effective address and then use a relative load */
+       base_addr = jit_insn_add(func, base_addr,
+               jit_insn_mul(func, index,
+                                        jit_value_create_nint_constant
+                                               (func, jit_type_nint, size)));
+       return jit_insn_load_relative(func, base_addr, 0, elem_type);
+}
+
+/*@
+ * @deftypefun jit_value_t jit_insn_load_elem_address (jit_function_t func, jit_value_t base_addr, jit_value_t index, jit_type_t elem_type)
+ * Load the effective address of an element of type @code{elem_type} at
+ * position @code{index} within the array starting at @code{base_addr}.
+ * Essentially, this computes the expression @code{base_addr + index *
+ * sizeof(elem_type)}, but may be more efficient than performing the
+ * steps with @code{jit_insn_mul} and @code{jit_insn_add}.
+ * @end deftypefun
+@*/
+jit_value_t jit_insn_load_elem_address
+       (jit_function_t func, jit_value_t base_addr,
+        jit_value_t index, jit_type_t elem_type)
+{
+       jit_nint size = (jit_nint)(jit_type_get_size(elem_type));
+       index = jit_insn_convert(func, index, jit_type_nint, 0);
+       return jit_insn_add(func, base_addr,
+               jit_insn_mul(func, index,
+                                        jit_value_create_nint_constant
+                                               (func, jit_type_nint, size)));
+}
+
+/*@
+ * @deftypefun int jit_insn_store_elem (jit_function_t func, jit_value_t base_addr, jit_value_t index, jit_value_t value)
+ * Store @code{value} at position @code{index} of the array starting at
+ * @code{base_addr}.  The effective address of the storage location is
+ * @code{base_addr + index * sizeof(jit_value_get_type(value))}.
+ * @end deftypefun
+@*/
+int jit_insn_store_elem
+       (jit_function_t func, jit_value_t base_addr,
+        jit_value_t index, jit_value_t value)
+{
+       jit_nint size;
+       int opcode;
+       jit_type_t elem_type;
+
+       /* Get the size of the element that we are fetching */
+       if(!value)
+       {
+               return 0;
+       }
+       elem_type = jit_value_get_type(value);
+       size = (jit_nint)(jit_type_get_size(elem_type));
+
+       /* Convert the index into a native integer */
+       index = jit_insn_convert(func, index, jit_type_nint, 0);
+       if(!index)
+       {
+               return 0;
+       }
+
+       /* If the index is constant, then turn this into a relative store */
+       if(jit_value_is_constant(index))
+       {
+               return jit_insn_store_relative
+                       (func, base_addr,
+                        jit_value_get_nint_constant(index) * size, value);
+       }
+
+       /* See if we can use a special-case instruction */
+       opcode = _jit_store_opcode(JIT_OP_STORE_ELEMENT_BYTE, 0, elem_type);
+       if(opcode != 0 && opcode != (JIT_OP_STORE_ELEMENT_BYTE + 7))
+       {
+               return apply_ternary(func, opcode, base_addr, index, value);
+       }
+
+       /* Calculate the effective address and then use a relative store */
+       base_addr = jit_insn_add(func, base_addr,
+               jit_insn_mul(func, index,
+                                        jit_value_create_nint_constant
+                                               (func, jit_type_nint, size)));
+       return jit_insn_store_relative(func, base_addr, 0, value);
+}
+
 /*@
  * @deftypefun int jit_insn_check_null (jit_function_t func, jit_value_t value)
  * Check @code{value} to see if it is NULL.  If it is, then throw the
@@ -6178,6 +6331,48 @@ jit_value_t jit_insn_call_filter
        return create_dest_note(func, JIT_OP_CALL_FILTER_RETURN, type);
 }
 
+/*@
+ * @deftypefun int jit_insn_memcpy (jit_function_t func, jit_value_t dest, jit_value_t src, jit_value_t size)
+ * Copy the @code{size} bytes of memory at @code{src} to @code{dest}.
+ * It is assumed that the source and destination do not overlap.
+ * @end deftypefun
+@*/
+int jit_insn_memcpy
+       (jit_function_t func, jit_value_t dest,
+        jit_value_t src, jit_value_t size)
+{
+       size = jit_insn_convert(func, size, jit_type_nint, 0);
+       return apply_ternary(func, JIT_OP_MEMCPY, dest, src, size);
+}
+
+/*@
+ * @deftypefun int jit_insn_memmove (jit_function_t func, jit_value_t dest, jit_value_t src, jit_value_t size)
+ * Copy the @code{size} bytes of memory at @code{src} to @code{dest}.
+ * This is save to use if the source and destination overlap.
+ * @end deftypefun
+@*/
+int jit_insn_memmove
+       (jit_function_t func, jit_value_t dest,
+        jit_value_t src, jit_value_t size)
+{
+       size = jit_insn_convert(func, size, jit_type_nint, 0);
+       return apply_ternary(func, JIT_OP_MEMMOVE, dest, src, size);
+}
+
+/*@
+ * @deftypefun int jit_insn_memset (jit_function_t func, jit_value_t dest, jit_value_t value, jit_value_t size)
+ * Set the @code{size} bytes at @code{dest} to @code{value}.
+ * @end deftypefun
+@*/
+int jit_insn_memset
+       (jit_function_t func, jit_value_t dest,
+        jit_value_t value, jit_value_t size)
+{
+       value = jit_insn_convert(func, value, jit_type_int, 0);
+       size = jit_insn_convert(func, size, jit_type_nint, 0);
+       return apply_ternary(func, JIT_OP_MEMSET, dest, value, size);
+}
+
 /*@
  * @deftypefun void jit_insn_iter_init ({jit_insn_iter_t *} iter, jit_block_t block)
  * Initialize an iterator to point to the first instruction in @code{block}.
index fae091f9baad415afca590105335315be695b078..8ec640cee7db3ece1821d44eef0d988f954c6400 100644 (file)
@@ -103,8 +103,20 @@ straight vanilla ANSI C.
 #define        VM_STK_NFLOATP  (stacktop[-1].nfloat_value)
 #define        VM_STK_PTR0             (stacktop[0].ptr_value)
 #define        VM_STK_PTR1             (stacktop[1].ptr_value)
+#define        VM_STK_PTR2             (stacktop[2].ptr_value)
 #define        VM_STK_PTRP             (stacktop[-1].ptr_value)
 #define        VM_STK_PTRP2    (stacktop[-2].ptr_value)
+#ifdef JIT_NATIVE_INT32
+#define        VM_STK_NINT0    VM_STK_INT0
+#define        VM_STK_NINT1    VM_STK_INT1
+#define        VM_STK_NUINT0   VM_STK_UINT0
+#define        VM_STK_NUINT1   VM_STK_UINT1
+#else
+#define        VM_STK_NINT0    VM_STK_LONG0
+#define        VM_STK_NINT1    VM_STK_LONG1
+#define        VM_STK_NUINT0   VM_STK_ULONG0
+#define        VM_STK_NUINT1   VM_STK_ULONG1
+#endif
 
 /*
  * Apply a relative adjustment to a pointer and cast to a specific type.
@@ -112,6 +124,14 @@ straight vanilla ANSI C.
 #define        VM_REL(type,ptr)        \
                        ((type *)(((unsigned char *)(ptr)) + VM_NINT_ARG))
 
+/*
+ * Apply an array adjustment to a pointer.
+ */
+#define        VM_LOAD_ELEM(type)      \
+                       (*(((type *)VM_STK_PTR1) + VM_STK_NINT0))
+#define        VM_STORE_ELEM(type,value)       \
+                       (*(((type *)VM_STK_PTR2) + VM_STK_NINT1) = (type)(value))
+
 /*
  * Get the address of an argument or local variable at a particular offset.
  */
@@ -3715,6 +3735,182 @@ void _jit_run_function(jit_function_interp *func, jit_item *args,
                }
                VMBREAK;
 
+               /******************************************************************
+                * Array element loads and stores.
+                ******************************************************************/
+
+               VMCASE(JIT_OP_LOAD_ELEMENT_SBYTE):
+               {
+                       /* Load a signed 8-bit integer value from an array */
+                       VM_STK_INT1 = VM_LOAD_ELEM(jit_sbyte);
+                       VM_MODIFY_PC_AND_STACK(1, 1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_LOAD_ELEMENT_UBYTE):
+               {
+                       /* Load an unsigned 8-bit integer value from an array */
+                       VM_STK_INT1 = VM_LOAD_ELEM(jit_ubyte);
+                       VM_MODIFY_PC_AND_STACK(1, 1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_LOAD_ELEMENT_SHORT):
+               {
+                       /* Load a signed 16-bit integer value from an array */
+                       VM_STK_INT1 = VM_LOAD_ELEM(jit_short);
+                       VM_MODIFY_PC_AND_STACK(1, 1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_LOAD_ELEMENT_USHORT):
+               {
+                       /* Load an unsigned 16-bit integer value from an array */
+                       VM_STK_INT1 = VM_LOAD_ELEM(jit_ushort);
+                       VM_MODIFY_PC_AND_STACK(1, 1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_LOAD_ELEMENT_INT):
+               {
+                       /* Load a signed 32-bit integer value from an array */
+                       VM_STK_INT1 = VM_LOAD_ELEM(jit_int);
+                       VM_MODIFY_PC_AND_STACK(1, 1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_LOAD_ELEMENT_UINT):
+               {
+                       /* Load an unsigned 32-bit integer value from an array */
+                       VM_STK_UINT1 = VM_LOAD_ELEM(jit_uint);
+                       VM_MODIFY_PC_AND_STACK(1, 1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_LOAD_ELEMENT_LONG):
+               {
+                       /* Load a signed 64-bit integer value from an array */
+                       VM_STK_LONG1 = VM_LOAD_ELEM(jit_long);
+                       VM_MODIFY_PC_AND_STACK(1, 1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_LOAD_ELEMENT_ULONG):
+               {
+                       /* Load an unsigned 64-bit integer value from an array */
+                       VM_STK_ULONG1 = VM_LOAD_ELEM(jit_ulong);
+                       VM_MODIFY_PC_AND_STACK(1, 1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_LOAD_ELEMENT_FLOAT32):
+               {
+                       /* Load a 32-bit float value from an array */
+                       VM_STK_FLOAT321 = VM_LOAD_ELEM(jit_float32);
+                       VM_MODIFY_PC_AND_STACK(1, 1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_LOAD_ELEMENT_FLOAT64):
+               {
+                       /* Load a 64-bit float value from an array */
+                       VM_STK_FLOAT641 = VM_LOAD_ELEM(jit_float64);
+                       VM_MODIFY_PC_AND_STACK(1, 1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_LOAD_ELEMENT_NFLOAT):
+               {
+                       /* Load a native float value from an array */
+                       VM_STK_NFLOAT1 = VM_LOAD_ELEM(jit_nfloat);
+                       VM_MODIFY_PC_AND_STACK(1, 1);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_STORE_ELEMENT_BYTE):
+               {
+                       /* Store a 8-bit integer value to an array */
+                       VM_STORE_ELEM(jit_sbyte, VM_STK_INT0);
+                       VM_MODIFY_PC_AND_STACK(1, 3);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_STORE_ELEMENT_SHORT):
+               {
+                       /* Store a 16-bit integer value to an array */
+                       VM_STORE_ELEM(jit_short, VM_STK_INT0);
+                       VM_MODIFY_PC_AND_STACK(1, 3);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_STORE_ELEMENT_INT):
+               {
+                       /* Store a 32-bit integer value to an array */
+                       VM_STORE_ELEM(jit_int, VM_STK_INT0);
+                       VM_MODIFY_PC_AND_STACK(1, 3);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_STORE_ELEMENT_LONG):
+               {
+                       /* Store a 64-bit integer value to an array */
+                       VM_STORE_ELEM(jit_long, VM_STK_LONG0);
+                       VM_MODIFY_PC_AND_STACK(1, 3);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_STORE_ELEMENT_FLOAT32):
+               {
+                       /* Store a 32-bit float value to an array */
+                       VM_STORE_ELEM(jit_float32, VM_STK_FLOAT320);
+                       VM_MODIFY_PC_AND_STACK(1, 3);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_STORE_ELEMENT_FLOAT64):
+               {
+                       /* Store a 64-bit float value to an array */
+                       VM_STORE_ELEM(jit_float64, VM_STK_FLOAT640);
+                       VM_MODIFY_PC_AND_STACK(1, 3);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_STORE_ELEMENT_NFLOAT):
+               {
+                       /* Store a native float value to an array */
+                       VM_STORE_ELEM(jit_nfloat, VM_STK_NFLOAT0);
+                       VM_MODIFY_PC_AND_STACK(1, 3);
+               }
+               VMBREAK;
+
+               /******************************************************************
+                * Block operations.
+                ******************************************************************/
+
+               VMCASE(JIT_OP_MEMCPY):
+               {
+                       /* Copy a block of memory */
+                       jit_memcpy(VM_STK_PTR2, VM_STK_PTR1, VM_STK_NUINT0);
+                       VM_MODIFY_PC_AND_STACK(1, 3);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_MEMMOVE):
+               {
+                       /* Move a block of memory */
+                       jit_memmove(VM_STK_PTR2, VM_STK_PTR1, VM_STK_NUINT0);
+                       VM_MODIFY_PC_AND_STACK(1, 3);
+               }
+               VMBREAK;
+
+               VMCASE(JIT_OP_MEMSET):
+               {
+                       /* Set a block of memory to a value */
+                       jit_memset(VM_STK_PTR2, (int)VM_STK_INT1, VM_STK_NUINT0);
+                       VM_MODIFY_PC_AND_STACK(1, 3);
+               }
+               VMBREAK;
+
                /******************************************************************
                 * Argument variable access opcodes.
                 ******************************************************************/
index ce864467002d2a94187006f68ba2982e572d9824..6ded14474f5dbea57ebcac44cf74b766360516d6 100644 (file)
@@ -485,6 +485,35 @@ jit_opcode_info_t const jit_opcodes[JIT_OP_NUM_OPCODES] = {
        {"store_relative_nfloat",               F_(PTR, NFLOAT, INT) | NINT_ARG},
        {"store_relative_struct",               F_(PTR, ANY, INT) | NINT_ARG_TWO},
        {"add_relative",                                F_(PTR, PTR, INT) | NINT_ARG},
+
+       /*
+        * Array element loads and stores.
+        */
+       {"load_element_sbyte",                  F_(INT, PTR, INT)},
+       {"load_element_ubyte",                  F_(INT, PTR, INT)},
+       {"load_element_short",                  F_(INT, PTR, INT)},
+       {"load_element_ushort",                 F_(INT, PTR, INT)},
+       {"load_element_int",                    F_(INT, PTR, INT)},
+       {"load_element_uint",                   F_(INT, PTR, INT)},
+       {"load_element_long",                   F_(LONG, PTR, INT)},
+       {"load_element_ulong",                  F_(LONG, PTR, INT)},
+       {"load_element_float32",                F_(FLOAT32, PTR, INT)},
+       {"load_element_float64",                F_(FLOAT64, PTR, INT)},
+       {"load_element_nfloat",                 F_(NFLOAT, PTR, INT)},
+       {"store_element_byte",                  F_(PTR, INT, INT)},
+       {"store_element_short",                 F_(PTR, INT, INT)},
+       {"store_element_int",                   F_(PTR, INT, INT)},
+       {"store_element_long",                  F_(PTR, INT, LONG)},
+       {"store_element_float32",               F_(PTR, INT, FLOAT32)},
+       {"store_element_float64",               F_(PTR, INT, FLOAT64)},
+       {"store_element_nfloat",                F_(PTR, INT, NFLOAT)},
+
+       /*
+        * Block operations.
+        */
+       {"memcpy",                                              F_(PTR, PTR, INT)},
+       {"memmove",                                             F_(PTR, PTR, INT)},
+       {"memset",                                              F_(PTR, INT, INT)},
 };
 
 #if defined(JIT_BACKEND_INTERP)
index be3312f91b61284bf9dcb62edb24a9ef2cd3b66b..d2790e57666eb1b7aa6d4c948551cbf788a505a9 100644 (file)
@@ -1114,7 +1114,7 @@ int _jit_regs_load_to_top_two
        if(value->in_register && value2->in_register)
        {
                reg = value->reg;
-               reg2 = value->reg;
+               reg2 = value2->reg;
                if((_jit_reg_info[gen->contents[reg2].remap].flags
                                & JIT_REG_START_STACK) != 0 &&
                   gen->contents[reg].remap == (gen->contents[reg2].remap + 1))
@@ -1160,6 +1160,63 @@ int _jit_regs_load_to_top_two
        return reg;
 }
 
+/*@
+ * @deftypefun void _jit_regs_load_to_top_three (jit_gencode_t gen, jit_value_t value, jit_value_t value2, jit_value_t value3, int used_again1, int used_again2, int used_again3, int type_reg)
+ * Load three values to the top of a register stack.  The values are assumed
+ * to be popped by the subsequent operation.  This is used by the interpreted
+ * back end for things like array stores, that need three values but all
+ * of them are discarded after the operation.
+ * @end deftypefun
+@*/
+void _jit_regs_load_to_top_three
+       (jit_gencode_t gen, jit_value_t value, jit_value_t value2,
+        jit_value_t value3, int used_again1, int used_again2,
+        int used_again3, int type_reg)
+{
+       int reg, reg2, reg3;
+
+       /* Determine if the values are already in the top three registers */
+       if(value->in_register && value2->in_register && value3->in_register)
+       {
+               reg = value->reg;
+               reg2 = value2->reg;
+               reg3 = value3->reg;
+               if((_jit_reg_info[gen->contents[reg2].remap].flags
+                               & JIT_REG_START_STACK) != 0 &&
+                  gen->contents[reg].remap == (gen->contents[reg2].remap + 1) &&
+                  gen->contents[reg2].remap == (gen->contents[reg3].remap + 1))
+               {
+                       if((value->in_frame || !used_again1) &&
+                          (value2->in_frame || !used_again2) &&
+                          (value3->in_frame || !used_again3))
+                       {
+                               /* Disassociate the values from the registers and return */
+                               free_stack_reg(gen, reg);
+                               free_stack_reg(gen, reg2);
+                               free_stack_reg(gen, reg3);
+                               value->in_register = 0;
+                               value2->in_register = 0;
+                               value3->in_register = 0;
+                               gen->contents[reg].used_for_temp = 0;
+                               gen->contents[reg2].used_for_temp = 0;
+                               gen->contents[reg3].used_for_temp = 0;
+                               return;
+                       }
+               }
+       }
+
+       /* Spill everything out, so that we know where things are */
+       spill_all_stack(gen, type_reg);
+
+       /* Load the three values that we want onto the stack */
+       reg = _jit_regs_load_value(gen, value, 1, used_again1);
+       reg2 = _jit_regs_load_value(gen, value2, 1, used_again2);
+       reg3 = _jit_regs_load_value(gen, value3, 1, used_again3);
+       gen->contents[reg].used_for_temp = 0;
+       gen->contents[reg2].used_for_temp = 0;
+       gen->contents[reg3].used_for_temp = 0;
+}
+
 /*@
  * @deftypefun int _jit_regs_num_used (jit_gencode_t gen, int type_reg)
  * Get the number of stack registers in use within the register stack
index f516e9652ba44e16b565266619c89260dd39774b..e44f28069700c0b892f2ed8c457feac1494f647d 100644 (file)
@@ -47,6 +47,10 @@ int _jit_regs_load_to_top
 int _jit_regs_load_to_top_two
        (jit_gencode_t gen, jit_value_t value, jit_value_t value2,
         int used_again1, int used_again2, int type_reg);
+void _jit_regs_load_to_top_three
+       (jit_gencode_t gen, jit_value_t value, jit_value_t value2,
+        jit_value_t value3, int used_again1, int used_again2,
+        int used_again3, int type_reg);
 int _jit_regs_num_used(jit_gencode_t gen, int type_reg);
 
 #ifdef __cplusplus
index 3ac69b1b342f0e631dc309360f875e5596a52d65..181ebb1acc88ff63ffdfb1b09bd24dc458694ab0 100644 (file)
@@ -1199,9 +1199,23 @@ void _jit_gen_insn(jit_gencode_t gen, jit_function_t func,
 
                default:
                {
-                       /* Whatever opcodes are left are binary or unary operators,
+                       /* Whatever opcodes are left are ordinary operators,
                           and the interpreter's opcode is identical to the JIT's */
-                       if(insn->value2)
+                       if(insn->value2 && (insn->flags & JIT_INSN_DEST_IS_VALUE) != 0)
+                       {
+                               /* Generate code for a ternary operator with no real dest */
+                               _jit_regs_load_to_top_three
+                                       (gen, insn->dest, insn->value1, insn->value2,
+                                        (insn->flags & (JIT_INSN_DEST_NEXT_USE |
+                                                                        JIT_INSN_DEST_LIVE)),
+                                        (insn->flags & (JIT_INSN_VALUE1_NEXT_USE |
+                                                                        JIT_INSN_VALUE1_LIVE)),
+                                        (insn->flags & (JIT_INSN_VALUE2_NEXT_USE |
+                                                                        JIT_INSN_VALUE2_LIVE)), 0);
+                               jit_cache_opcode(&(gen->posn), insn->opcode);
+                               adjust_working(gen, -3);
+                       }
+                       else if(insn->value2)
                        {
                                /* Generate code for a binary operator */
                                reg = _jit_regs_load_to_top_two
index cf858d4313e1e1b8fbdea7fd382e68e45f269110..4adee3cba0731607b38757842640918af37b8cfa 100644 (file)
@@ -566,6 +566,9 @@ jit_value jit_function::get_struct_pointer()
  * @deftypemethodx jit_function jit_value insn_load_relative ({const jit_value&} value, jit_nint offset, jit_type_t type)
  * @deftypemethodx jit_function void insn_store_relative ({const jit_value&} dest, jit_nint offset, {const jit_value&} value)
  * @deftypemethodx jit_function jit_value insn_add_relative ({const jit_value&} value, jit_nint offset)
+ * @deftypemethodx jit_function jit_value insn_load_elem ({const jit_value&} base_addr, {const jit_value&} index, jit_type_t elem_type)
+ * @deftypemethodx jit_function jit_value insn_load_elem_address ({const jit_value&} base_addr, {const jit_value&} index, jit_type_t elem_type)
+ * @deftypemethodx jit_function void insn_store_elem ({const jit_value&} base_addr, {const jit_value&} index, {const jit_value&} value)
  * @deftypemethodx jit_function void insn_check_null ({const jit_value&} value)
  * @deftypemethodx jit_function jit_value insn_add ({const jit_value&} value1, {const jit_value&} value2)
  * @deftypemethodx jit_function jit_value insn_add_ovf ({const jit_value&} value1, {const jit_value&} value2)
@@ -637,6 +640,9 @@ jit_value jit_function::get_struct_pointer()
  * @deftypemethodx jit_function void insn_default_return ()
  * @deftypemethodx jit_function void insn_throw ({const jit_value&} value)
  * @deftypemethodx jit_function jit_value insn_get_call_stack ()
+ * @deftypemethodx jit_function void insn_memcpy ({const jit_value&} dest, {const jit_value&} src, {const jit_value&} size)
+ * @deftypemethodx void insn_memmove ({const jit_value&} dest, {const jit_value&} src, {const jit_value&} size)
+ * @deftypemethodx void jit_insn_memset ({const jit_value&} dest, {const jit_value&} value, {const jit_value&} size)
  * Create instructions of various kinds.  @xref{Instructions}, for more
  * information on the individual instructions and their arguments.
  * @end deftypemethod
@@ -694,6 +700,32 @@ jit_value jit_function::insn_add_relative
        value_wrap(jit_insn_add_relative(func, value.raw(), offset));
 }
 
+jit_value jit_function::insn_load_elem
+       (const jit_value& base_addr, const jit_value& index,
+        jit_type_t elem_type)
+{
+       value_wrap(jit_insn_load_elem
+               (func, base_addr.raw(), index.raw(), elem_type));
+}
+
+jit_value jit_function::insn_load_elem_address
+       (const jit_value& base_addr, const jit_value& index,
+        jit_type_t elem_type)
+{
+       value_wrap(jit_insn_load_elem_address
+               (func, base_addr.raw(), index.raw(), elem_type));
+}
+
+void jit_function::insn_store_elem
+       (const jit_value& base_addr, const jit_value& index,
+        const jit_value& value)
+{
+       if(!jit_insn_store_elem(func, base_addr.raw(), index.raw(), value.raw()))
+       {
+               out_of_memory();
+       }
+}
+
 void jit_function::insn_check_null(const jit_value& value)
 {
        if(!jit_insn_check_null(func, value.raw()))
@@ -1119,6 +1151,33 @@ jit_value jit_function::insn_get_call_stack()
        value_wrap(jit_insn_get_call_stack(func));
 }
 
+void jit_function::insn_memcpy
+       (const jit_value& dest, const jit_value& src, const jit_value& size)
+{
+       if(!jit_insn_memcpy(func, dest.raw(), src.raw(), size.raw()))
+       {
+               out_of_memory();
+       }
+}
+
+void jit_function::insn_memmove
+       (const jit_value& dest, const jit_value& src, const jit_value& size)
+{
+       if(!jit_insn_memmove(func, dest.raw(), src.raw(), size.raw()))
+       {
+               out_of_memory();
+       }
+}
+
+void jit_function::insn_memset
+       (const jit_value& dest, const jit_value& value, const jit_value& size)
+{
+       if(!jit_insn_memset(func, dest.raw(), value.raw(), size.raw()))
+       {
+               out_of_memory();
+       }
+}
+
 void jit_function::register_on_demand()
 {
        jit_function_set_on_demand_compiler(func, on_demand_compiler);