* 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,
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
(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;
#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.
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);
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;
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.
*/
}
}
+/*@
+ * @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
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}.
#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.
#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.
*/
}
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.
******************************************************************/
{"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)
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))
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
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
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
* @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)
* @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
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()))
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);