From: Rhys Weatherley Date: Sun, 13 Jun 2004 01:48:58 +0000 (+0000) Subject: Add the "outgoing_frame_posn" instruction, to support tail calls. X-Git-Tag: r.0.0.4~15 X-Git-Url: https://git.unchartedbackwaters.co.uk/w/?a=commitdiff_plain;h=0f17c4bcbc2b24eb98d3a2c6dcb3fc3206ba6975;p=francis%2Flibjit.git Add the "outgoing_frame_posn" instruction, to support tail calls. --- diff --git a/ChangeLog b/ChangeLog index 5052cb1..68a3827 100644 --- a/ChangeLog +++ b/ChangeLog @@ -4,6 +4,12 @@ * 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 * doc/libjit.texi, jit/jit-insn.c, jit/jit-internal.h, diff --git a/include/jit/jit-insn.h b/include/jit/jit-insn.h index 1ce9cc1..340115f 100644 --- a/include/jit/jit-insn.h +++ b/include/jit/jit-insn.h @@ -241,6 +241,8 @@ int jit_insn_incoming_frame_posn (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 diff --git a/include/jit/jit-opcode.h b/include/jit/jit-opcode.h index 5223b51..a5bb59b 100644 --- a/include/jit/jit-opcode.h +++ b/include/jit/jit-opcode.h @@ -438,81 +438,82 @@ extern "C" { #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. diff --git a/include/jit/jit-plus.h b/include/jit/jit-plus.h index d8cb174..d958a69 100644 --- a/include/jit/jit-plus.h +++ b/include/jit/jit-plus.h @@ -308,6 +308,7 @@ public: 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); diff --git a/jit/jit-function.c b/jit/jit-function.c index a8212c8..578622b 100644 --- a/jit/jit-function.c +++ b/jit/jit-function.c @@ -495,6 +495,19 @@ static void compile_block(jit_gencode_t gen, jit_function_t func, } 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 */ diff --git a/jit/jit-insn.c b/jit/jit-insn.c index dcf7c43..c72961e 100644 --- a/jit/jit-insn.c +++ b/jit/jit-insn.c @@ -5968,6 +5968,24 @@ int jit_insn_outgoing_reg(jit_function_t func, jit_value_t value, int reg) (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} diff --git a/jit/jit-interp.c b/jit/jit-interp.c index 39a0fc5..b92fb76 100644 --- a/jit/jit-interp.c +++ b/jit/jit-interp.c @@ -4478,6 +4478,7 @@ void _jit_run_function(jit_function_interp_t func, jit_item *args, 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): diff --git a/jit/jit-opcode.c b/jit/jit-opcode.c index f71ed9b..ac0aa1e 100644 --- a/jit/jit-opcode.c +++ b/jit/jit-opcode.c @@ -454,6 +454,7 @@ jit_opcode_info_t const jit_opcodes[JIT_OP_NUM_OPCODES] = { {"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)}, diff --git a/jit/jit-rules-interp.c b/jit/jit-rules-interp.c index 4d3d5e1..183a222 100644 --- a/jit/jit-rules-interp.c +++ b/jit/jit-rules-interp.c @@ -381,63 +381,128 @@ int _jit_create_call_setup_insns 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 */ diff --git a/jitplus/jit-plus-function.cpp b/jitplus/jit-plus-function.cpp index 38b9a86..1541b00 100644 --- a/jitplus/jit-plus-function.cpp +++ b/jitplus/jit-plus-function.cpp @@ -639,6 +639,7 @@ jit_value jit_function::get_struct_pointer() * @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) @@ -1174,6 +1175,15 @@ void jit_function::insn_outgoing_reg(const jit_value& value, int reg) } } +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))