From: Rhys Weatherley Date: Sat, 1 May 2004 07:25:52 +0000 (+0000) Subject: Add array access instructions. X-Git-Tag: r.0.0.2~40 X-Git-Url: https://git.unchartedbackwaters.co.uk/w/?a=commitdiff_plain;h=660d16f453e633bf95502998e97b1f30173ba722;p=francis%2Flibjit.git Add array access instructions. --- diff --git a/ChangeLog b/ChangeLog index 4a28a9a..ef747d8 100644 --- a/ChangeLog +++ b/ChangeLog @@ -10,6 +10,12 @@ * 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 * include/jit/jit-function.h, include/jit/jit-insn.h, diff --git a/include/jit/jit-insn.h b/include/jit/jit-insn.h index b0f9d35..d5b1a84 100644 --- a/include/jit/jit-insn.h +++ b/include/jit/jit-insn.h @@ -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; diff --git a/include/jit/jit-opcode.h b/include/jit/jit-opcode.h index fc7e7d1..2b08ecd 100644 --- a/include/jit/jit-opcode.h +++ b/include/jit/jit-opcode.h @@ -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. diff --git a/include/jit/jit-plus.h b/include/jit/jit-plus.h index 920600e..051ef65 100644 --- a/include/jit/jit-plus.h +++ b/include/jit/jit-plus.h @@ -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; diff --git a/jit/jit-insn.c b/jit/jit-insn.c index efafa90..6de9057 100644 --- a/jit/jit-insn.c +++ b/jit/jit-insn.c @@ -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}. diff --git a/jit/jit-interp.cpp b/jit/jit-interp.cpp index fae091f..8ec640c 100644 --- a/jit/jit-interp.cpp +++ b/jit/jit-interp.cpp @@ -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. ******************************************************************/ diff --git a/jit/jit-opcode.c b/jit/jit-opcode.c index ce86446..6ded144 100644 --- a/jit/jit-opcode.c +++ b/jit/jit-opcode.c @@ -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) diff --git a/jit/jit-reg-alloc.c b/jit/jit-reg-alloc.c index be3312f..d2790e5 100644 --- a/jit/jit-reg-alloc.c +++ b/jit/jit-reg-alloc.c @@ -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 diff --git a/jit/jit-reg-alloc.h b/jit/jit-reg-alloc.h index f516e96..e44f280 100644 --- a/jit/jit-reg-alloc.h +++ b/jit/jit-reg-alloc.h @@ -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 diff --git a/jit/jit-rules-interp.c b/jit/jit-rules-interp.c index 3ac69b1..181ebb1 100644 --- a/jit/jit-rules-interp.c +++ b/jit/jit-rules-interp.c @@ -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 diff --git a/jitplus/jit-plus-function.cpp b/jitplus/jit-plus-function.cpp index cf858d4..4adee3c 100644 --- a/jitplus/jit-plus-function.cpp +++ b/jitplus/jit-plus-function.cpp @@ -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);