From b68a43a6579f5c762039d31d9cd27f06e520c3c9 Mon Sep 17 00:00:00 2001 From: Rhys Weatherley Date: Tue, 11 May 2004 02:04:17 +0000 Subject: [PATCH] Round out the function call handling opcodes for the interpreter. --- ChangeLog | 6 ++ include/jit/jit-insn.h | 2 + jit/jit-insn.c | 59 +++++++++++++++++-- jit/jit-interp.cpp | 49 ++++++++++++---- jit/jit-interp.h | 6 +- jit/jit-opcode.c | 6 +- jit/jit-rules-interp.c | 128 ++++++++++++++++++++++++++++++++++++++--- 7 files changed, 227 insertions(+), 29 deletions(-) diff --git a/ChangeLog b/ChangeLog index a2c9515..e81a63c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,10 @@ +2004-05-11 Rhys Weatherley + + * include/jit/jit-insn.h, jit/jit-insn.c, jit/jit-interp.cpp, + jit/jit-interp.h, jit/jit-opcode.c, jit/jit-rules-interp.c: + round out the function call handling opcodes for the interpreter. + 2004-05-10 Rhys Weatherley * jit/jit-reg-alloc.c, jit/jit-reg-alloc.h, jit/jit-rules-interp.c: diff --git a/include/jit/jit-insn.h b/include/jit/jit-insn.h index f667c3f..01b85e8 100644 --- a/include/jit/jit-insn.h +++ b/include/jit/jit-insn.h @@ -246,6 +246,8 @@ int jit_insn_flush_struct(jit_function_t func, jit_value_t value) JIT_NOTHROW; jit_value_t jit_insn_import (jit_function_t func, jit_value_t value) JIT_NOTHROW; int jit_insn_push(jit_function_t func, jit_value_t value) JIT_NOTHROW; +int jit_insn_push_ptr + (jit_function_t func, jit_value_t value, jit_type_t type) JIT_NOTHROW; int jit_insn_pop_stack(jit_function_t func, jit_nint num_items) JIT_NOTHROW; int jit_insn_return(jit_function_t func, jit_value_t value) JIT_NOTHROW; int jit_insn_return_ptr diff --git a/jit/jit-insn.c b/jit/jit-insn.c index b12e48f..731fa1e 100644 --- a/jit/jit-insn.c +++ b/jit/jit-insn.c @@ -4994,7 +4994,9 @@ jit_value_t jit_insn_call_indirect } jit_value_ref(func, value); insn->opcode = JIT_OP_CALL_INDIRECT; + insn->flags = JIT_INSN_VALUE2_IS_SIGNATURE; insn->value1 = value; + insn->value2 = (jit_value_t)jit_type_copy(signature); /* If the function does not return, then end the current block. The next block does not have "entered_via_top" set so that @@ -5593,7 +5595,6 @@ int jit_insn_flush_struct(jit_function_t func, jit_value_t value) * @deftypefun jit_value_t jit_insn_import (jit_function_t func, jit_value_t value) * Import @code{value} from an outer nested scope into @code{func}. Returns * the effective address of the value for local access via a pointer. - * If @code{value} is local to @code{func}, then it is returned as-is. * Returns NULL if out of memory or the value is not accessible via a * parent, grandparent, or other ancestor of @code{func}. * @end deftypefun @@ -5610,11 +5611,11 @@ jit_value_t jit_insn_import(jit_function_t func, jit_value_t value) return 0; } - /* If the value is already local, then there is nothing to do */ + /* If the value is already local, then return the local address */ value_func = jit_value_get_function(value); if(value_func == func) { - return value; + return jit_insn_address_of(func, value); } /* Find the nesting level of the value, where 1 is our parent */ @@ -5695,13 +5696,63 @@ int jit_insn_push(jit_function_t func, jit_value_t value) case JIT_TYPE_STRUCT: case JIT_TYPE_UNION: { - return create_unary_note(func, JIT_OP_PUSH_STRUCT, value); + /* We need the address of the value for "push_struct" */ + value = jit_insn_address_of(func, value); + if(!value) + { + return 0; + } + return create_note + (func, JIT_OP_PUSH_STRUCT, value, + jit_value_create_nint_constant + (func, jit_type_nint, (jit_nint)jit_type_get_size(type))); } /* Not reached */ } return 1; } +/*@ + * @deftypefun int jit_insn_push_ptr (jit_function_t func, jit_value_t value, jit_type_t type) + * Push @code{*value} onto the function call stack, in preparation for a call. + * This is normally used for returning @code{struct} and @code{union} + * values where you have the effective address of the structure, rather + * than the structure's contents, in @code{value}. + * + * You normally wouldn't call this yourself - it is used internally + * by the CPU back ends to set up the stack for a subroutine call. + * @end deftypefun +@*/ +int jit_insn_push_ptr + (jit_function_t func, jit_value_t value, jit_type_t type) +{ + if(!value || !type) + { + return 0; + } + switch(jit_type_normalize(type)->kind) + { + case JIT_TYPE_STRUCT: + case JIT_TYPE_UNION: + { + /* Push the structure onto the stack by address */ + return create_note + (func, JIT_OP_PUSH_STRUCT, value, + jit_value_create_nint_constant + (func, jit_type_nint, (jit_nint)jit_type_get_size(type))); + } + /* Not reached */ + + default: + { + /* Load the value from the address and push it normally */ + return jit_insn_push + (func, jit_insn_load_relative(func, value, 0, type)); + } + /* Not reached */ + } +} + /*@ * @deftypefun int jit_insn_pop_stack (jit_function_t func, jit_nint num_items) * Pop @code{num_items} items from the function call stack. You normally diff --git a/jit/jit-interp.cpp b/jit/jit-interp.cpp index 8e463a0..7f18793 100644 --- a/jit/jit-interp.cpp +++ b/jit/jit-interp.cpp @@ -3294,6 +3294,7 @@ void _jit_run_function(jit_function_interp *func, jit_item *args, ******************************************************************/ VMCASE(JIT_OP_CALL): + VMCASE(JIT_OP_CALL_TAIL): { /* Call a function that is under the control of the JIT */ call_func = (jit_function_t)VM_NINT_ARG; @@ -3455,8 +3456,8 @@ void _jit_run_function(jit_function_interp *func, jit_item *args, { /* Return from the current function, with a small structure */ #if JIT_APPLY_MAX_STRUCT_IN_REG != 0 - jit_memcpy(return_area->struct_value, VM_STK_PTR1, - (unsigned int)VM_STK_NINT0); + jit_memcpy(return_area->struct_value, VM_STK_PTR0, + (unsigned int)VM_NINT_ARG); #endif return; } @@ -3488,19 +3489,46 @@ void _jit_run_function(jit_function_interp *func, jit_item *args, } VMBREAK; - VMCASE(JIT_OP_PUSH_PARENT_LOCALS): + VMCASE(JIT_OP_IMPORT_LOCAL): { - /* Push the pointer to the parent's local variables */ - VM_STK_PTRP = args[0].ptr_value; - VM_MODIFY_PC_AND_STACK(1, -1); + /* Import the address of a local variable from an outer scope */ + temparg = VM_NINT_ARG2; + tempptr = args[0].ptr_value; + tempptr2 = args[1].ptr_value; + while(temparg > 1) + { + tempptr = ((jit_item *)tempptr2)[0].ptr_value; + tempptr2 = ((jit_item *)tempptr2)[1].ptr_value; + --temparg; + } + VM_STK_PTRP = ((jit_item *)tempptr) + VM_NINT_ARG; + VM_MODIFY_PC_AND_STACK(3, -1); } VMBREAK; - VMCASE(JIT_OP_PUSH_PARENT_ARGS): + VMCASE(JIT_OP_IMPORT_ARG): { - /* Push the pointer to the parent's argument variables */ - VM_STK_PTRP = args[1].ptr_value; - VM_MODIFY_PC_AND_STACK(1, -1); + /* Import the address of an argument from an outer scope */ + temparg = VM_NINT_ARG2; + tempptr = args[1].ptr_value; + while(temparg > 1) + { + tempptr = ((jit_item *)tempptr)[1].ptr_value; + --temparg; + } + VM_STK_PTRP = ((jit_item *)tempptr) + VM_NINT_ARG; + VM_MODIFY_PC_AND_STACK(3, -1); + } + VMBREAK; + + VMCASE(JIT_OP_PUSH_STRUCT): + { + /* Push a structure value onto the stack, given a pointer to it */ + tempptr = VM_STK_PTR0; + temparg = VM_NINT_ARG; + stacktop -= (JIT_NUM_ITEMS_IN_STRUCT(temparg) - 1); + jit_memcpy(stacktop, tempptr, (unsigned int)temparg); + VM_MODIFY_PC_AND_STACK(2, 0); } VMBREAK; @@ -4405,7 +4433,6 @@ void _jit_run_function(jit_function_interp *func, jit_item *args, VMCASE(JIT_OP_PUSH_FLOAT32): VMCASE(JIT_OP_PUSH_FLOAT64): VMCASE(JIT_OP_PUSH_NFLOAT): - VMCASE(JIT_OP_PUSH_STRUCT): VMCASE(JIT_OP_FLUSH_SMALL_STRUCT): VMCASE(JIT_OP_END_MARKER): VMCASE(JIT_OP_ENTER_CATCH): diff --git a/jit/jit-interp.h b/jit/jit-interp.h index 7a12506..c23b0a5 100644 --- a/jit/jit-interp.h +++ b/jit/jit-interp.h @@ -171,8 +171,8 @@ public: /* * Nested function call handling. */ -#define JIT_OP_PUSH_PARENT_LOCALS (JIT_OP_NUM_OPCODES + 0x0031) -#define JIT_OP_PUSH_PARENT_ARGS (JIT_OP_NUM_OPCODES + 0x0032) +#define JIT_OP_IMPORT_LOCAL (JIT_OP_NUM_OPCODES + 0x0031) +#define JIT_OP_IMPORT_ARG (JIT_OP_NUM_OPCODES + 0x0032) /* * Push constant values onto the stack. @@ -191,7 +191,7 @@ public: /* * Marker opcode for the end of the interpreter-specific opcodes. */ -#define JIT_OP_END_MARKER (JIT_OP_NUM_OPCODES + 0x0039) +#define JIT_OP_END_MARKER (JIT_OP_NUM_OPCODES + 0x003B) /* * Number of interpreter-specific opcodes. diff --git a/jit/jit-opcode.c b/jit/jit-opcode.c index e3a8d43..591ac0d 100644 --- a/jit/jit-opcode.c +++ b/jit/jit-opcode.c @@ -459,7 +459,7 @@ jit_opcode_info_t const jit_opcodes[JIT_OP_NUM_OPCODES] = { {"push_float32", F_(EMPTY, FLOAT32, EMPTY)}, {"push_float64", F_(EMPTY, FLOAT64, EMPTY)}, {"push_nfloat", F_(EMPTY, NFLOAT, EMPTY)}, - {"push_struct", F_(EMPTY, ANY, EMPTY)}, + {"push_struct", F_(EMPTY, ANY, PTR) | NINT_ARG}, {"pop_stack", F_(EMPTY, INT, EMPTY) | NINT_ARG}, {"flush_small_struct", F_(EMPTY, ANY, EMPTY)}, @@ -588,8 +588,8 @@ jit_opcode_info_t const _jit_interp_opcodes[JIT_OP_NUM_INTERP_OPCODES] = { /* * Nested function call handling. */ - {"push_parent_locals", 0}, - {"push_parent_args", 0}, + {"import_local", JIT_OPCODE_NINT_ARG_TWO}, + {"import_arg", JIT_OPCODE_NINT_ARG_TWO}, /* * Push constant values onto the stack. diff --git a/jit/jit-rules-interp.c b/jit/jit-rules-interp.c index 91e5e61..f5620b2 100644 --- a/jit/jit-rules-interp.c +++ b/jit/jit-rules-interp.c @@ -375,12 +375,27 @@ int _jit_create_call_setup_insns int is_nested, int nested_level, jit_value_t *struct_return) { jit_type_t type; + jit_type_t vtype; jit_value_t value; /* Push all of the arguments in reverse order */ while(num_args > 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) + { + /* 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) + { + if(!jit_insn_push_ptr(func, args[num_args], type)) + { + return 0; + } + } + } if(!jit_insn_push(func, args[num_args])) { return 0; @@ -1056,6 +1071,7 @@ void _jit_gen_insn(jit_gencode_t gen, jit_function_t func, /* Not reached */ case JIT_OP_CALL: + case JIT_OP_CALL_TAIL: { /* Call a function, whose pointer is supplied explicitly */ jit_cache_opcode(&(gen->posn), insn->opcode); @@ -1063,32 +1079,50 @@ void _jit_gen_insn(jit_gencode_t gen, jit_function_t func, } break; - case JIT_OP_CALL_EXTERNAL: + case JIT_OP_CALL_INDIRECT: { - /* Call a native function, whose pointer is supplied explicitly */ + /* Call a function, whose pointer is supplied on the stack */ if(!jit_type_return_via_pointer (jit_type_get_return((jit_type_t)(insn->value2)))) { jit_cache_opcode(&(gen->posn), JIT_OP_PUSH_RETURN_AREA_PTR); } + reg = _jit_regs_load_to_top(gen, insn->value1, 0, 0); jit_cache_opcode(&(gen->posn), insn->opcode); jit_cache_native(&(gen->posn), (jit_nint)(insn->value2)); - jit_cache_native(&(gen->posn), (jit_nint)(insn->dest)); jit_cache_native(&(gen->posn), (jit_nint) (jit_type_num_params((jit_type_t)(insn->value2)))); + _jit_regs_free_reg(gen, reg, 1); + adjust_working(gen, -1); } break; - case JIT_OP_CALL_INDIRECT: case JIT_OP_CALL_VTABLE_PTR: { - /* Call a function, whose pointer is supplied on the stack */ - _jit_regs_load_to_top(gen, insn->value1, 0, 0); + /* Call a function, whose vtable pointer is supplied on the stack */ + reg = _jit_regs_load_to_top(gen, insn->value1, 0, 0); jit_cache_opcode(&(gen->posn), insn->opcode); + _jit_regs_free_reg(gen, reg, 1); adjust_working(gen, -1); } break; + case JIT_OP_CALL_EXTERNAL: + { + /* Call a native function, whose pointer is supplied explicitly */ + if(!jit_type_return_via_pointer + (jit_type_get_return((jit_type_t)(insn->value2)))) + { + jit_cache_opcode(&(gen->posn), JIT_OP_PUSH_RETURN_AREA_PTR); + } + jit_cache_opcode(&(gen->posn), insn->opcode); + jit_cache_native(&(gen->posn), (jit_nint)(insn->value2)); + jit_cache_native(&(gen->posn), (jit_nint)(insn->dest)); + jit_cache_native(&(gen->posn), (jit_nint) + (jit_type_num_params((jit_type_t)(insn->value2)))); + } + break; + case JIT_OP_RETURN: { /* Return from the current function with no result */ @@ -1115,6 +1149,68 @@ void _jit_gen_insn(jit_gencode_t gen, jit_function_t func, } break; + case JIT_OP_RETURN_SMALL_STRUCT: + { + /* Return from current function with a small structure result */ + if(!_jit_regs_is_top(gen, insn->value1) || + _jit_regs_num_used(gen, 0) != 1) + { + _jit_regs_spill_all(gen); + } + reg = _jit_regs_load_to_top(gen, insn->value1, 0, 0); + jit_cache_opcode(&(gen->posn), insn->opcode); + jit_cache_native(&(gen->posn), + jit_value_get_nint_constant(insn->value2)); + _jit_regs_free_reg(gen, reg, 1); + } + break; + + case JIT_OP_SETUP_FOR_NESTED: + { + /* Set up to call a nested child */ + jit_cache_opcode(&(gen->posn), insn->opcode); + adjust_working(gen, 2); + } + break; + + case JIT_OP_SETUP_FOR_SIBLING: + { + /* Set up to call a nested sibling */ + jit_cache_opcode(&(gen->posn), insn->opcode); + jit_cache_native(&(gen->posn), + jit_value_get_nint_constant(insn->value1)); + adjust_working(gen, 2); + } + break; + + case JIT_OP_IMPORT: + { + /* Import a local variable from an outer nested scope */ + if(_jit_regs_num_used(gen, 0) >= JIT_NUM_REGS) + { + _jit_regs_spill_all(gen); + } + _jit_gen_fix_value(insn->value1); + if(insn->value1->frame_offset >= 0) + { + jit_cache_opcode(&(gen->posn), JIT_OP_IMPORT_LOCAL); + jit_cache_native(&(gen->posn), insn->value1->frame_offset); + jit_cache_native(&(gen->posn), + jit_value_get_nint_constant(insn->value2)); + } + else + { + jit_cache_opcode(&(gen->posn), JIT_OP_IMPORT_ARG); + jit_cache_native + (&(gen->posn), -(insn->value1->frame_offset + 1)); + jit_cache_native(&(gen->posn), + jit_value_get_nint_constant(insn->value2)); + } + reg = _jit_regs_new_top(gen, insn->dest, 0); + adjust_working(gen, 1); + } + break; + case JIT_OP_RETURN_REG: { /* Push a function return value back onto the stack */ @@ -1232,14 +1328,30 @@ void _jit_gen_insn(jit_gencode_t gen, jit_function_t func, case JIT_OP_PUSH_STRUCT: { - /* TODO */ + /* Load the pointer value to the top of the stack */ + if(!_jit_regs_is_top(gen, insn->value1) || + _jit_regs_num_used(gen, 0) != 1) + { + _jit_regs_spill_all(gen); + } + reg = _jit_regs_load_to_top + (gen, insn->value1, + (insn->flags & (JIT_INSN_VALUE1_NEXT_USE | + JIT_INSN_VALUE1_LIVE)), 0); + _jit_regs_free_reg(gen, reg, 1); + + /* Push the structure at the designated pointer */ + size = jit_value_get_nint_constant(insn->value2); + jit_cache_opcode(&(gen->posn), insn->opcode); + jit_cache_native(&(gen->posn), size); + adjust_working(gen, JIT_NUM_ITEMS_IN_STRUCT(size) - 1); } break; case JIT_OP_POP_STACK: { /* Pop parameter values from the stack after a function returns */ - jit_nint size = jit_value_get_nint_constant(insn->value1); + size = jit_value_get_nint_constant(insn->value1); if(size == 1) { jit_cache_opcode(&(gen->posn), JIT_OP_POP); -- 2.47.3