/*
* Compile a single basic block within a function.
*/
-static void compile_block(jit_gencode_t gen, jit_function_t func,
- jit_block_t block)
+static void
+compile_block(jit_gencode_t gen, jit_function_t func, jit_block_t block)
{
jit_insn_iter_t iter;
jit_insn_t insn;
switch(insn->opcode)
{
- case JIT_OP_NOP: break; /* Ignore NOP's */
+ case JIT_OP_NOP:
+ /* Ignore NOP's */
+ break;
- case JIT_OP_CHECK_NULL:
+ case JIT_OP_CHECK_NULL:
+ /* Determine if we can optimize the null check away */
+ if(!_jit_insn_check_is_redundant(&iter))
{
- /* Determine if we can optimize the null check away */
- if(!_jit_insn_check_is_redundant(&iter))
- {
- _jit_gen_insn(gen, func, block, insn);
- }
+ _jit_gen_insn(gen, func, block, insn);
}
break;
+ case JIT_OP_CALL:
+ case JIT_OP_CALL_TAIL:
+ case JIT_OP_CALL_INDIRECT:
+ case JIT_OP_CALL_INDIRECT_TAIL:
+ case JIT_OP_CALL_VTABLE_PTR:
+ case JIT_OP_CALL_VTABLE_PTR_TAIL:
+ case JIT_OP_CALL_EXTERNAL:
+ case JIT_OP_CALL_EXTERNAL_TAIL:
+ /* Spill all caller-saved registers before a call */
+ _jit_regs_spill_all(gen);
+ _jit_gen_insn(gen, func, block, insn);
+ break;
+
#ifndef JIT_BACKEND_INTERP
- case JIT_OP_INCOMING_REG:
- {
- /* Assign a register to an incoming value */
- _jit_regs_set_incoming
- (gen, (int)jit_value_get_nint_constant(insn->value2),
- insn->value1);
- _jit_gen_insn(gen, func, block, insn);
- }
+ case JIT_OP_INCOMING_REG:
+ /* Assign a register to an incoming value */
+ _jit_regs_set_incoming(gen,
+ (int)jit_value_get_nint_constant(insn->value2),
+ insn->value1);
+ _jit_gen_insn(gen, func, block, insn);
break;
#endif
- case JIT_OP_INCOMING_FRAME_POSN:
+ case JIT_OP_INCOMING_FRAME_POSN:
+ /* Set the frame position for an incoming value */
+ insn->value1->frame_offset = jit_value_get_nint_constant(insn->value2);
+ insn->value1->in_register = 0;
+ insn->value1->has_frame_offset = 1;
+ if(insn->value1->has_global_register)
{
- /* Set the frame position for an incoming value */
- insn->value1->frame_offset =
- jit_value_get_nint_constant(insn->value2);
- insn->value1->in_register = 0;
- insn->value1->has_frame_offset = 1;
- if(insn->value1->has_global_register)
- {
- insn->value1->in_global_register = 1;
- _jit_gen_load_global(gen, insn->value1->global_reg, insn->value1);
- }
- else
- {
- insn->value1->in_frame = 1;
- }
+ insn->value1->in_global_register = 1;
+ _jit_gen_load_global(gen, insn->value1->global_reg, insn->value1);
+ }
+ else
+ {
+ insn->value1->in_frame = 1;
}
break;
#ifndef JIT_BACKEND_INTERP
- case JIT_OP_OUTGOING_REG:
- {
- /* Copy a value into an outgoing register */
- _jit_regs_set_outgoing
- (gen, (int)jit_value_get_nint_constant(insn->value2),
- insn->value1);
- }
+ case JIT_OP_OUTGOING_REG:
+ /* Copy a value into an outgoing register */
+ _jit_regs_set_outgoing(gen,
+ (int)jit_value_get_nint_constant(insn->value2),
+ insn->value1);
break;
#endif
- 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;
- }
+ 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;
#ifndef JIT_BACKEND_INTERP
- case JIT_OP_RETURN_REG:
- {
- /* Assign a register to a return value */
- _jit_regs_set_incoming
- (gen, (int)jit_value_get_nint_constant(insn->value2),
- insn->value1);
- _jit_gen_insn(gen, func, block, insn);
- }
+ case JIT_OP_RETURN_REG:
+ /* Assign a register to a return value */
+ _jit_regs_set_incoming(gen,
+ (int)jit_value_get_nint_constant(insn->value2),
+ insn->value1);
+ _jit_gen_insn(gen, func, block, insn);
break;
#endif
- case JIT_OP_MARK_OFFSET:
- {
- /* Mark the current code position as corresponding
- to a particular bytecode offset */
- _jit_cache_mark_bytecode
- (&(gen->posn), (unsigned long)(long)
- jit_value_get_nint_constant(insn->value1));
- }
+ case JIT_OP_MARK_OFFSET:
+ /* Mark the current code position as corresponding
+ to a particular bytecode offset */
+ _jit_cache_mark_bytecode(&gen->posn,
+ (unsigned long)(long)
+ jit_value_get_nint_constant(insn->value1));
break;
- default:
- {
- /* Generate code for the instruction with the back end */
- _jit_gen_insn(gen, func, block, insn);
- }
+ default:
+ /* Generate code for the instruction with the back end */
+ _jit_gen_insn(gen, func, block, insn);
break;
}
is_nested, nesting_level, struct_return, flags);
}
+static jit_value_t
+handle_return(jit_function_t func,
+ jit_type_t signature,
+ int flags, int is_nested,
+ jit_value_t *args, unsigned int num_args,
+ jit_value_t return_value)
+{
+ /* If the function does not return, then end the current block.
+ The next block does not have "entered_via_top" set so that
+ it will be eliminated during later code generation */
+ if((flags & (JIT_CALL_NORETURN | JIT_CALL_TAIL)) != 0)
+ {
+ func->builder->current_block->ends_in_dead = 1;
+ }
+
+ /* If the function may throw an exceptions then end the current
+ basic block to account for exceptional control flow */
+ if((flags & JIT_CALL_NOTHROW) == 0)
+ {
+ if(!jit_insn_new_block(func))
+ {
+ return 0;
+ }
+ }
+
+ /* Create space for the return value, if we don't already have one */
+ if(!return_value)
+ {
+ return_value = jit_value_create(func, jit_type_get_return(signature));
+ if(!return_value)
+ {
+ return 0;
+ }
+ }
+
+ /* Create the instructions necessary to move the return value into place */
+ if((flags & JIT_CALL_TAIL) == 0)
+ {
+ if(!_jit_create_call_return_insns(func,
+ signature,
+ args, num_args,
+ return_value,
+ is_nested))
+ {
+ return 0;
+ }
+ }
+
+ /* Restore exception frame information after the call */
+ if(!restore_eh_frame_after_call(func, flags))
+ {
+ return 0;
+ }
+
+ /* Return the value containing the result to the caller */
+ return return_value;
+}
+
/*@
* @deftypefun jit_value_t jit_insn_call (jit_function_t @var{func}, const char *@var{name}, jit_function_t @var{jit_func}, jit_type_t @var{signature}, jit_value_t *@var{args}, unsigned int @var{num_args}, int @var{flags})
* Call the function @var{jit_func}, which may or may not be translated yet.
return 0;
}
- /* Start a new block and output the "call" instruction */
+ /* Output the "call" instruction */
if((flags & JIT_CALL_TAIL) != 0 && func == jit_func)
{
/* We are performing a tail call to ourselves, which we can
func->builder->non_leaf = 1;
/* Performing a regular call, or a tail call to someone else */
- if(!jit_insn_new_block(func))
- {
- return 0;
- }
insn = _jit_block_add_insn(func->builder->current_block);
if(!insn)
{
insn->value1 = (jit_value_t)name;
}
- /* If the function does not return, then end the current block.
- The next block does not have "entered_via_top" set so that
- it will be eliminated during later code generation */
- if((flags & (JIT_CALL_NORETURN | JIT_CALL_TAIL)) != 0)
- {
- func->builder->current_block->ends_in_dead = 1;
- if(!jit_insn_new_block(func))
- {
- return 0;
- }
- }
-
- /* Create space for the return value, if we don't already have one */
- if(!return_value)
- {
- return_value = jit_value_create(func, jit_type_get_return(signature));
- if(!return_value)
- {
- return 0;
- }
- }
-
- /* Create the instructions necessary to move the return value into place */
- if((flags & JIT_CALL_TAIL) == 0)
- {
- if(!_jit_create_call_return_insns
- (func, signature, new_args, num_args, return_value, is_nested))
- {
- return 0;
- }
- }
-
- /* Restore exception frame information after the call */
- if(!restore_eh_frame_after_call(func, flags))
- {
- return 0;
- }
-
- /* Return the value containing the result to the caller */
- return return_value;
+ /* Handle return to the caller */
+ return handle_return(func, signature, flags, is_nested,
+ new_args, num_args, return_value);
}
/*@
/* Functions that call out are not leaves */
func->builder->non_leaf = 1;
- /* Start a new block and output the "call_indirect" instruction */
- if(!jit_insn_new_block(func))
- {
- return 0;
- }
+ /* Output the "call_indirect" instruction */
insn = _jit_block_add_insn(func->builder->current_block);
if(!insn)
{
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
- it will be eliminated during later code generation */
- if((flags & (JIT_CALL_NORETURN | JIT_CALL_TAIL)) != 0)
- {
- func->builder->current_block->ends_in_dead = 1;
- if(!jit_insn_new_block(func))
- {
- return 0;
- }
- }
-
- /* Create space for the return value, if we don't already have one */
- if(!return_value)
- {
- return_value = jit_value_create(func, jit_type_get_return(signature));
- if(!return_value)
- {
- return 0;
- }
- }
-
- /* Create the instructions necessary to move the return value into place */
- if((flags & JIT_CALL_TAIL) == 0)
- {
- if(!_jit_create_call_return_insns
- (func, signature, new_args, num_args, return_value, 0))
- {
- return 0;
- }
- }
-
- /* Restore exception frame information after the call */
- if(!restore_eh_frame_after_call(func, flags))
- {
- return 0;
- }
-
- /* Return the value containing the result to the caller */
- return return_value;
+ /* Handle return to the caller */
+ return handle_return(func, signature, flags, 0,
+ new_args, num_args, return_value);
}
/*@
/* Functions that call out are not leaves */
func->builder->non_leaf = 1;
- /* Start a new block and output the "call_vtable_ptr" instruction */
- if(!jit_insn_new_block(func))
- {
- return 0;
- }
+ /* Output the "call_vtable_ptr" instruction */
insn = _jit_block_add_insn(func->builder->current_block);
if(!insn)
{
}
insn->value1 = value;
- /* If the function does not return, then end the current block.
- The next block does not have "entered_via_top" set so that
- it will be eliminated during later code generation */
- if((flags & (JIT_CALL_NORETURN | JIT_CALL_TAIL)) != 0)
- {
- func->builder->current_block->ends_in_dead = 1;
- if(!jit_insn_new_block(func))
- {
- return 0;
- }
- }
-
- /* Create space for the return value, if we don't already have one */
- if(!return_value)
- {
- return_value = jit_value_create(func, jit_type_get_return(signature));
- if(!return_value)
- {
- return 0;
- }
- }
-
- /* Create the instructions necessary to move the return value into place */
- if((flags & JIT_CALL_TAIL) == 0)
- {
- if(!_jit_create_call_return_insns
- (func, signature, new_args, num_args, return_value, 0))
- {
- return 0;
- }
- }
-
- /* Restore exception frame information after the call */
- if(!restore_eh_frame_after_call(func, flags))
- {
- return 0;
- }
-
- /* Return the value containing the result to the caller */
- return return_value;
+ /* Handle return to the caller */
+ return handle_return(func, signature, flags, 0,
+ new_args, num_args, return_value);
}
/*@
/* Functions that call out are not leaves */
func->builder->non_leaf = 1;
- /* Start a new block and output the "call_external" instruction */
- if(!jit_insn_new_block(func))
- {
- return 0;
- }
+ /* Output the "call_external" instruction */
insn = _jit_block_add_insn(func->builder->current_block);
if(!insn)
{
insn->value2 = (jit_value_t)jit_type_copy(signature);
#endif
- /* If the function does not return, then end the current block.
- The next block does not have "entered_via_top" set so that
- it will be eliminated during later code generation */
- if((flags & (JIT_CALL_NORETURN | JIT_CALL_TAIL)) != 0)
- {
- func->builder->current_block->ends_in_dead = 1;
- if(!jit_insn_new_block(func))
- {
- return 0;
- }
- }
-
- /* Create space for the return value, if we don't already have one */
- if(!return_value)
- {
- return_value = jit_value_create(func, jit_type_get_return(signature));
- if(!return_value)
- {
- return 0;
- }
- }
-
- /* Create the instructions necessary to move the return value into place */
- if((flags & JIT_CALL_TAIL) == 0)
- {
- if(!_jit_create_call_return_insns
- (func, signature, new_args, num_args, return_value, 0))
- {
- return 0;
- }
- }
+ /* Handle return to the caller */
+ return_value = handle_return(func, signature, flags, 0,
+ new_args, num_args, return_value);
/* Make sure that returned byte / short values get zero / sign extended */
return_type = jit_type_normalize(return_value->type);
break;
}
- /* Restore exception frame information after the call */
- if(!restore_eh_frame_after_call(func, flags))
- {
- return 0;
- }
-
/* Return the value containing the result to the caller */
return return_value;
}