Browse Source

Round out the function call handling opcodes for the interpreter.

cache-refactoring
Rhys Weatherley 21 years ago
parent
commit
b68a43a657
  1. 6
      ChangeLog
  2. 2
      include/jit/jit-insn.h
  3. 59
      jit/jit-insn.c
  4. 49
      jit/jit-interp.cpp
  5. 6
      jit/jit-interp.h
  6. 6
      jit/jit-opcode.c
  7. 128
      jit/jit-rules-interp.c

6
ChangeLog

@ -1,4 +1,10 @@
2004-05-11 Rhys Weatherley <rweather@southern-storm.com.au>
* 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 <rweather@southern-storm.com.au>
* jit/jit-reg-alloc.c, jit/jit-reg-alloc.h, jit/jit-rules-interp.c:

2
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

59
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

49
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):

6
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.

6
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.

128
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);

Loading…
Cancel
Save