* jit/jit-insn.c, jit/jit-rules-x86.c, jit/jit-rules-x86.sel:
implement or stub missing x86 instruction selection rules.
+ * include/jit/jit-insn.h, include/jit/jit-opcode.h,
+ include/jit/jit-plus.h, jit/jit-function.c, jit/jit-insn.c,
+ jit/jit-interp.c, jit/jit-opcode.c, jit/jit-rules-interp.c,
+ jitplus/jit-plus-function.cpp: add the "outgoing_frame_posn"
+ instruction, to support tail calls.
+
2004-06-11 Rhys Weatherley <rweather@southern-storm.com.au>
* doc/libjit.texi, jit/jit-insn.c, jit/jit-internal.h,
(jit_function_t func, jit_value_t value, jit_nint frame_offset) JIT_NOTHROW;
int jit_insn_outgoing_reg
(jit_function_t func, jit_value_t value, int reg) JIT_NOTHROW;
+int jit_insn_outgoing_frame_posn
+ (jit_function_t func, jit_value_t value, jit_nint frame_offset) JIT_NOTHROW;
int jit_insn_return_reg
(jit_function_t func, jit_value_t value, int reg) JIT_NOTHROW;
int jit_insn_setup_for_nested
#define JIT_OP_INCOMING_REG 0x0165
#define JIT_OP_INCOMING_FRAME_POSN 0x0166
#define JIT_OP_OUTGOING_REG 0x0167
-#define JIT_OP_RETURN_REG 0x0168
-#define JIT_OP_PUSH_INT 0x0169
-#define JIT_OP_PUSH_LONG 0x016A
-#define JIT_OP_PUSH_FLOAT32 0x016B
-#define JIT_OP_PUSH_FLOAT64 0x016C
-#define JIT_OP_PUSH_NFLOAT 0x016D
-#define JIT_OP_PUSH_STRUCT 0x016E
-#define JIT_OP_POP_STACK 0x016F
-#define JIT_OP_FLUSH_SMALL_STRUCT 0x0170
-#define JIT_OP_SET_PARAM_INT 0x0171
-#define JIT_OP_SET_PARAM_LONG 0x0172
-#define JIT_OP_SET_PARAM_FLOAT32 0x0173
-#define JIT_OP_SET_PARAM_FLOAT64 0x0174
-#define JIT_OP_SET_PARAM_NFLOAT 0x0175
-#define JIT_OP_SET_PARAM_STRUCT 0x0176
+#define JIT_OP_OUTGOING_FRAME_POSN 0x0168
+#define JIT_OP_RETURN_REG 0x0169
+#define JIT_OP_PUSH_INT 0x016A
+#define JIT_OP_PUSH_LONG 0x016B
+#define JIT_OP_PUSH_FLOAT32 0x016C
+#define JIT_OP_PUSH_FLOAT64 0x016D
+#define JIT_OP_PUSH_NFLOAT 0x016E
+#define JIT_OP_PUSH_STRUCT 0x016F
+#define JIT_OP_POP_STACK 0x0170
+#define JIT_OP_FLUSH_SMALL_STRUCT 0x0171
+#define JIT_OP_SET_PARAM_INT 0x0172
+#define JIT_OP_SET_PARAM_LONG 0x0173
+#define JIT_OP_SET_PARAM_FLOAT32 0x0174
+#define JIT_OP_SET_PARAM_FLOAT64 0x0175
+#define JIT_OP_SET_PARAM_NFLOAT 0x0176
+#define JIT_OP_SET_PARAM_STRUCT 0x0177
/*
* Pointer-relative loads and stores.
*/
-#define JIT_OP_LOAD_RELATIVE_SBYTE 0x0177
-#define JIT_OP_LOAD_RELATIVE_UBYTE 0x0178
-#define JIT_OP_LOAD_RELATIVE_SHORT 0x0179
-#define JIT_OP_LOAD_RELATIVE_USHORT 0x017A
-#define JIT_OP_LOAD_RELATIVE_INT 0x017B
-#define JIT_OP_LOAD_RELATIVE_LONG 0x017C
-#define JIT_OP_LOAD_RELATIVE_FLOAT32 0x017D
-#define JIT_OP_LOAD_RELATIVE_FLOAT64 0x017E
-#define JIT_OP_LOAD_RELATIVE_NFLOAT 0x017F
-#define JIT_OP_LOAD_RELATIVE_STRUCT 0x0180
-#define JIT_OP_STORE_RELATIVE_BYTE 0x0181
-#define JIT_OP_STORE_RELATIVE_SHORT 0x0182
-#define JIT_OP_STORE_RELATIVE_INT 0x0183
-#define JIT_OP_STORE_RELATIVE_LONG 0x0184
-#define JIT_OP_STORE_RELATIVE_FLOAT32 0x0185
-#define JIT_OP_STORE_RELATIVE_FLOAT64 0x0186
-#define JIT_OP_STORE_RELATIVE_NFLOAT 0x0187
-#define JIT_OP_STORE_RELATIVE_STRUCT 0x0188
-#define JIT_OP_ADD_RELATIVE 0x0189
+#define JIT_OP_LOAD_RELATIVE_SBYTE 0x0178
+#define JIT_OP_LOAD_RELATIVE_UBYTE 0x0179
+#define JIT_OP_LOAD_RELATIVE_SHORT 0x017A
+#define JIT_OP_LOAD_RELATIVE_USHORT 0x017B
+#define JIT_OP_LOAD_RELATIVE_INT 0x017C
+#define JIT_OP_LOAD_RELATIVE_LONG 0x017D
+#define JIT_OP_LOAD_RELATIVE_FLOAT32 0x017E
+#define JIT_OP_LOAD_RELATIVE_FLOAT64 0x017F
+#define JIT_OP_LOAD_RELATIVE_NFLOAT 0x0180
+#define JIT_OP_LOAD_RELATIVE_STRUCT 0x0181
+#define JIT_OP_STORE_RELATIVE_BYTE 0x0182
+#define JIT_OP_STORE_RELATIVE_SHORT 0x0183
+#define JIT_OP_STORE_RELATIVE_INT 0x0184
+#define JIT_OP_STORE_RELATIVE_LONG 0x0185
+#define JIT_OP_STORE_RELATIVE_FLOAT32 0x0186
+#define JIT_OP_STORE_RELATIVE_FLOAT64 0x0187
+#define JIT_OP_STORE_RELATIVE_NFLOAT 0x0188
+#define JIT_OP_STORE_RELATIVE_STRUCT 0x0189
+#define JIT_OP_ADD_RELATIVE 0x018A
/*
* Array element loads and stores.
*/
-#define JIT_OP_LOAD_ELEMENT_SBYTE 0x018A
-#define JIT_OP_LOAD_ELEMENT_UBYTE 0x018B
-#define JIT_OP_LOAD_ELEMENT_SHORT 0x018C
-#define JIT_OP_LOAD_ELEMENT_USHORT 0x018D
-#define JIT_OP_LOAD_ELEMENT_INT 0x018E
-#define JIT_OP_LOAD_ELEMENT_LONG 0x018F
-#define JIT_OP_LOAD_ELEMENT_FLOAT32 0x0190
-#define JIT_OP_LOAD_ELEMENT_FLOAT64 0x0191
-#define JIT_OP_LOAD_ELEMENT_NFLOAT 0x0192
-#define JIT_OP_STORE_ELEMENT_BYTE 0x0193
-#define JIT_OP_STORE_ELEMENT_SHORT 0x0194
-#define JIT_OP_STORE_ELEMENT_INT 0x0195
-#define JIT_OP_STORE_ELEMENT_LONG 0x0196
-#define JIT_OP_STORE_ELEMENT_FLOAT32 0x0197
-#define JIT_OP_STORE_ELEMENT_FLOAT64 0x0198
-#define JIT_OP_STORE_ELEMENT_NFLOAT 0x0199
+#define JIT_OP_LOAD_ELEMENT_SBYTE 0x018B
+#define JIT_OP_LOAD_ELEMENT_UBYTE 0x018C
+#define JIT_OP_LOAD_ELEMENT_SHORT 0x018D
+#define JIT_OP_LOAD_ELEMENT_USHORT 0x018E
+#define JIT_OP_LOAD_ELEMENT_INT 0x018F
+#define JIT_OP_LOAD_ELEMENT_LONG 0x0190
+#define JIT_OP_LOAD_ELEMENT_FLOAT32 0x0191
+#define JIT_OP_LOAD_ELEMENT_FLOAT64 0x0192
+#define JIT_OP_LOAD_ELEMENT_NFLOAT 0x0193
+#define JIT_OP_STORE_ELEMENT_BYTE 0x0194
+#define JIT_OP_STORE_ELEMENT_SHORT 0x0195
+#define JIT_OP_STORE_ELEMENT_INT 0x0196
+#define JIT_OP_STORE_ELEMENT_LONG 0x0197
+#define JIT_OP_STORE_ELEMENT_FLOAT32 0x0198
+#define JIT_OP_STORE_ELEMENT_FLOAT64 0x0199
+#define JIT_OP_STORE_ELEMENT_NFLOAT 0x019A
/*
* Block operations.
*/
-#define JIT_OP_MEMCPY 0x019A
-#define JIT_OP_MEMMOVE 0x019B
-#define JIT_OP_MEMSET 0x019C
+#define JIT_OP_MEMCPY 0x019B
+#define JIT_OP_MEMMOVE 0x019C
+#define JIT_OP_MEMSET 0x019D
/*
* Allocate memory from the stack.
*/
-#define JIT_OP_ALLOCA 0x019D
+#define JIT_OP_ALLOCA 0x019E
/*
* The number of opcodes in the above list.
*/
-#define JIT_OP_NUM_OPCODES 0x019E
+#define JIT_OP_NUM_OPCODES 0x019F
/*
* Opcode information.
void insn_incoming_reg(const jit_value& value, int reg);
void insn_incoming_frame_posn(const jit_value& value, jit_nint posn);
void insn_outgoing_reg(const jit_value& value, int reg);
+ void insn_outgoing_frame_posn(const jit_value& value, jit_nint posn);
void insn_return_reg(const jit_value& value, int reg);
void insn_setup_for_nested(int nested_level, int reg);
void insn_flush_struct(const jit_value& value);
}
break;
+ case JIT_OP_OUTGOING_FRAME_POSN:
+ {
+ /* Set the frame position for an outgoing value */
+ insn->value1->frame_offset =
+ jit_value_get_nint_constant(insn->value2);
+ insn->value1->in_register = 0;
+ insn->value1->in_global_register = 0;
+ insn->value1->in_frame = 0;
+ insn->value1->has_frame_offset = 1;
+ insn->value1->has_global_register = 0;
+ }
+ break;
+
case JIT_OP_RETURN_REG:
{
/* Assign a register to a return value */
(func, jit_type_int, (jit_nint)reg));
}
+/*@
+ * @deftypefun int jit_insn_outgoing_frame_posn (jit_function_t func, jit_value_t value, jit_nint frame_offset)
+ * Output an instruction that notes that the contents of @code{value}
+ * should be stored in the stack frame at @code{frame_offset} at this point
+ * in the code.
+ *
+ * You normally wouldn't call this yourself - it is used internally
+ * by the CPU back ends to set up an outgoing frame for tail calls.
+ * @end deftypefun
+@*/
+int jit_insn_outgoing_frame_posn
+ (jit_function_t func, jit_value_t value, jit_nint frame_offset)
+{
+ return create_note(func, JIT_OP_OUTGOING_FRAME_POSN, value,
+ jit_value_create_nint_constant
+ (func, jit_type_int, frame_offset));
+}
+
/*@
* @deftypefun int jit_insn_return_reg (jit_function_t func, jit_value_t value, int reg)
* Output an instruction that notes that the contents of @code{value}
VMCASE(JIT_OP_INCOMING_REG):
VMCASE(JIT_OP_INCOMING_FRAME_POSN):
VMCASE(JIT_OP_OUTGOING_REG):
+ VMCASE(JIT_OP_OUTGOING_FRAME_POSN):
VMCASE(JIT_OP_RETURN_REG):
VMCASE(JIT_OP_PUSH_INT):
VMCASE(JIT_OP_PUSH_LONG):
{"incoming_reg", JIT_OPCODE_IS_REG},
{"incoming_frame_posn", F_(EMPTY, ANY, INT)},
{"outgoing_reg", JIT_OPCODE_IS_REG},
+ {"outgoing_frame_posn", F_(EMPTY, ANY, INT)},
{"return_reg", JIT_OPCODE_IS_REG},
{"push_int", F_(EMPTY, INT, EMPTY)},
{"push_long", F_(EMPTY, LONG, EMPTY)},
jit_type_t type;
jit_type_t vtype;
jit_value_t value;
+ unsigned int arg_num;
+ jit_nint offset;
+ jit_nuint size;
- /* Push all of the arguments in reverse order */
- while(num_args > 0)
+ /* Regular or tail call? */
+ if((flags & JIT_CALL_TAIL) == 0)
{
- --num_args;
- type = jit_type_normalize(jit_type_get_param(signature, num_args));
- if(type->kind == JIT_TYPE_STRUCT || type->kind == JIT_TYPE_UNION)
+ /* Push all of the arguments in reverse order */
+ while(num_args > 0)
{
- /* If the value is a pointer, then we are pushing a structure
- argument by pointer rather than by local variable */
- vtype = jit_type_normalize(jit_value_get_type(args[num_args]));
- if(vtype->kind <= JIT_TYPE_MAX_PRIMITIVE)
+ --num_args;
+ type = jit_type_normalize(jit_type_get_param(signature, num_args));
+ if(type->kind == JIT_TYPE_STRUCT || type->kind == JIT_TYPE_UNION)
{
- if(!jit_insn_push_ptr(func, args[num_args], type))
+ /* If the value is a pointer, then we are pushing a structure
+ argument by pointer rather than by local variable */
+ vtype = jit_type_normalize(jit_value_get_type(args[num_args]));
+ if(vtype->kind <= JIT_TYPE_MAX_PRIMITIVE)
{
- return 0;
+ if(!jit_insn_push_ptr(func, args[num_args], type))
+ {
+ return 0;
+ }
+ continue;
}
}
+ if(!jit_insn_push(func, args[num_args]))
+ {
+ return 0;
+ }
}
- if(!jit_insn_push(func, args[num_args]))
- {
- return 0;
- }
- }
- /* Do we need to add a structure return pointer argument? */
- type = jit_type_get_return(signature);
- if(jit_type_return_via_pointer(type))
- {
- value = jit_value_create(func, type);
- if(!value)
+ /* Do we need to add a structure return pointer argument? */
+ type = jit_type_get_return(signature);
+ if(jit_type_return_via_pointer(type))
{
- return 0;
+ value = jit_value_create(func, type);
+ if(!value)
+ {
+ return 0;
+ }
+ *struct_return = value;
+ value = jit_insn_address_of(func, value);
+ if(!value)
+ {
+ return 0;
+ }
+ if(!jit_insn_push(func, value))
+ {
+ return 0;
+ }
}
- *struct_return = value;
- value = jit_insn_address_of(func, value);
- if(!value)
+ else
{
- return 0;
+ *struct_return = 0;
}
- if(!jit_insn_push(func, value))
+
+ /* Do we need to add nested function scope information? */
+ if(is_nested)
{
- return 0;
+ if(!jit_insn_setup_for_nested(func, nested_level, -1))
+ {
+ return 0;
+ }
}
}
else
{
- *struct_return = 0;
- }
-
- /* Do we need to add nested function scope information? */
- if(is_nested)
- {
- if(!jit_insn_setup_for_nested(func, nested_level, -1))
+ /* Copy the arguments into our own parameter slots */
+ offset = -1;
+ if(func->nested_parent)
{
- return 0;
+ offset -= 2;
+ }
+ type = jit_type_get_return(signature);
+ if(jit_type_return_via_pointer(type))
+ {
+ --offset;
+ }
+ for(arg_num = 0; arg_num < num_args; ++arg_num)
+ {
+ type = jit_type_get_param(signature, arg_num);
+ value = jit_value_create(func, type);
+ if(!value)
+ {
+ return 0;
+ }
+ if(!jit_insn_outgoing_frame_posn(func, value, offset))
+ {
+ return 0;
+ }
+ type = jit_type_normalize(type);
+ size = jit_type_get_size(type);
+ offset -= (jit_nint)(JIT_NUM_ITEMS_IN_STRUCT(size));
+ if(type->kind == JIT_TYPE_STRUCT || type->kind == JIT_TYPE_UNION)
+ {
+ /* If the value is a pointer, then we are pushing a structure
+ argument by pointer rather than by local variable */
+ vtype = jit_type_normalize(jit_value_get_type(args[arg_num]));
+ if(vtype->kind <= JIT_TYPE_MAX_PRIMITIVE)
+ {
+ value = jit_insn_address_of(func, value);
+ if(!value)
+ {
+ return 0;
+ }
+ if(!jit_insn_memcpy
+ (func, value, args[arg_num],
+ jit_value_create_nint_constant
+ (func, jit_type_nint, (jit_nint)size)))
+ {
+ return 0;
+ }
+ continue;
+ }
+ }
+ if(!jit_insn_store(func, value, args[arg_num]))
+ {
+ return 0;
+ }
}
+ *struct_return = 0;
}
/* The call is ready to proceed */
* @deftypemethodx jit_function void insn_incoming_reg ({const jit_value&} value, int reg)
* @deftypemethodx jit_function void insn_incoming_frame_posn ({const jit_value&} value, jit_nint posn)
* @deftypemethodx jit_function void insn_outgoing_reg ({const jit_value&} value, int reg)
+ * @deftypemethodx jit_function void insn_outgoing_frame_posn ({const jit_value&} value, jit_nint posn)
* @deftypemethodx jit_function void insn_return_reg ({const jit_value&} value, int reg)
* @deftypemethodx jit_function void insn_setup_for_nested (int nested_level, int reg)
* @deftypemethodx jit_function void insn_flush_struct ({const jit_value&} value)
}
}
+void jit_function::insn_outgoing_frame_posn
+ (const jit_value& value, jit_nint posn)
+{
+ if(!jit_insn_outgoing_frame_posn(func, value.raw(), posn))
+ {
+ out_of_memory();
+ }
+}
+
void jit_function::insn_return_reg(const jit_value& value, int reg)
{
if(!jit_insn_return_reg(func, value.raw(), reg))