Alien-LibJIT
view release on metacpan or search on metacpan
libjit/jit/jit-insn.c view on Meta::CPAN
return 1;
}
else
{
return 0;
}
}
/*@
* @deftypefun void jit_insn_label (jit_function_t @var{func}, jit_label_t *@var{label})
* Start a new basic block within the function @var{func} and give it the
* specified @var{label}. If the call is made when a new block was just
* created by any previous call then that block is reused, no new block
* is created. Returns zero if out of memory.
*
* If the contents of @var{label} are @code{jit_label_undefined}, then this
* function will allocate a new label for this block. Otherwise it will
* reuse the specified label from a previous branch instruction.
* @end deftypefun
@*/
int
jit_insn_label(jit_function_t func, jit_label_t *label)
{
jit_block_t block;
if(!_jit_function_ensure_builder(func))
{
return 0;
}
if(!jit_insn_flush_defer_pop(func, 0))
{
return 0;
}
/* Create a new block if the current one is not empty */
block = func->builder->current_block;
if(_jit_block_get_last(block))
{
block = _jit_block_create(func);
if(!block)
{
return 0;
}
}
/* Record the label */
if(*label == jit_label_undefined)
{
*label = (func->builder->next_label)++;
}
if(!_jit_block_record_label(block, *label))
{
_jit_block_destroy(block);
return 0;
}
/* If the block is newly created then insert it to the end of
the function's block list */
if(block != func->builder->current_block)
{
_jit_block_attach_before(func->builder->exit_block, block, block);
func->builder->current_block = block;
}
return 1;
}
/*@
* @deftypefun int jit_insn_new_block (jit_function_t @var{func})
* Start a new basic block, without giving it an explicit label.
* @end deftypefun
@*/
int
jit_insn_new_block(jit_function_t func)
{
jit_block_t block;
#ifdef _JIT_BLOCK_DEBUG
jit_label_t label;
#endif
/* Create a new block */
block = _jit_block_create(func);
if(!block)
{
return 0;
}
#ifdef _JIT_BLOCK_DEBUG
label = (func->builder->next_label)++;
if(!_jit_block_record_label(block, label))
{
_jit_block_destroy(block);
return 0;
}
#endif
/* Insert the block to the end of the function's block list */
_jit_block_attach_before(func->builder->exit_block, block, block);
func->builder->current_block = block;
return 1;
}
int _jit_load_opcode(int base_opcode, jit_type_t type,
jit_value_t value, int no_temps)
{
type = jit_type_normalize(type);
if(!type)
{
return 0;
}
switch(type->kind)
{
case JIT_TYPE_SBYTE:
{
return base_opcode;
}
/* Not reached */
case JIT_TYPE_UBYTE:
{
return base_opcode + 1;
}
/* Not reached */
case JIT_TYPE_SHORT:
{
return base_opcode + 2;
}
/* Not reached */
case JIT_TYPE_USHORT:
{
return base_opcode + 3;
}
/* Not reached */
case JIT_TYPE_INT:
case JIT_TYPE_UINT:
{
if(no_temps && value && (value->is_temporary || value->is_local))
{
return 0;
}
return base_opcode + 4;
}
/* Not reached */
case JIT_TYPE_LONG:
case JIT_TYPE_ULONG:
{
if(no_temps && value && (value->is_temporary || value->is_local))
{
return 0;
}
return base_opcode + 5;
}
/* Not reached */
libjit/jit/jit-insn.c view on Meta::CPAN
/* Round the size to the best alignment boundary on this platform */
size = jit_insn_convert(func, size, jit_type_nuint, 0);
size = jit_insn_add
(func, size, jit_value_create_nint_constant
(func, jit_type_nuint, JIT_BEST_ALIGNMENT - 1));
size = jit_insn_and
(func, size, jit_value_create_nint_constant
(func, jit_type_nuint, ~((jit_nint)(JIT_BEST_ALIGNMENT - 1))));
/* Allocate "size" bytes of memory from the stack */
return apply_unary(func, JIT_OP_ALLOCA, size, jit_type_void_ptr);
}
/*@
* @deftypefun int jit_insn_move_blocks_to_end (jit_function_t @var{func}, jit_label_t @var{from_label}, jit_label_t @var{to_label})
* Move all of the blocks between @var{from_label} (inclusive) and
* @var{to_label} (exclusive) to the end of the current function.
* This is typically used to move the expression in a @code{while}
* loop to the end of the body, where it can be executed more
* efficiently.
* @end deftypefun
@*/
int jit_insn_move_blocks_to_end
(jit_function_t func, jit_label_t from_label, jit_label_t to_label)
{
jit_block_t first, last, block;
/* Make sure that deferred stack pops are flushed */
if(!jit_insn_flush_defer_pop(func, 0))
{
return 0;
}
/* Find the first block that needs to be moved */
first = jit_block_from_label(func, from_label);
if(!first)
{
return 0;
}
/* Find the last block that needs to be moved */
last = jit_block_from_label(func, to_label);
if(!last)
{
return 0;
}
/* Sanity check -- the last block has to be after the first */
for(block = first->next; block != last; block = block->next)
{
if (!block) {
return 0;
}
}
/* The last block is excluded from the blocks to move */
block = last->prev;
/* Move the blocks to the end */
_jit_block_detach(first, block);
_jit_block_attach_before(func->builder->exit_block, first, block);
func->builder->current_block = block;
/* Create a new block after the last one we moved, to start fresh */
return jit_insn_new_block(func);
}
/*@
* @deftypefun int jit_insn_move_blocks_to_start (jit_function_t @var{func}, jit_label_t @var{from_label}, jit_label_t @var{to_label})
* Move all of the blocks between @var{from_label} (inclusive) and
* @var{to_label} (exclusive) to the start of the current function.
* This is typically used to move initialization code to the head
* of the function.
* @end deftypefun
@*/
int jit_insn_move_blocks_to_start
(jit_function_t func, jit_label_t from_label, jit_label_t to_label)
{
jit_block_t init, first, last, block;
/* Make sure that deferred stack pops are flushed */
if(!jit_insn_flush_defer_pop(func, 0))
{
return 0;
}
/* Find the first block that needs to be moved */
first = jit_block_from_label(func, from_label);
if(!first)
{
return 0;
}
/* Find the last block that needs to be moved */
last = jit_block_from_label(func, to_label);
if(!last)
{
return 0;
}
/* Init block */
init = func->builder->init_block;
/* Sanity check -- the first block has to be after the init */
for(block = init->next; block != first; block = block->next)
{
if (!block) {
return 0;
}
}
/* Sanity check -- the last block has to be after the first */
for(block = first->next; block != last; block = block->next)
{
if (!block) {
return 0;
}
}
/* The last block is excluded from the blocks to move */
block = last->prev;
/* Update the init block pointer */
func->builder->init_block = block;
/* Move the blocks after the original init block */
if(init->next != first)
{
_jit_block_detach(first, block);
_jit_block_attach_after(init, first, block);
}
/* Done */
return 1;
}
/*@
* @deftypefun int jit_insn_mark_offset (jit_function_t @var{func}, jit_int @var{offset})
* Mark the current position in @var{func} as corresponding to the
* specified bytecode @var{offset}. This value will be returned
* by @code{jit_stack_trace_get_offset}, and is useful for associating
* code positions with source line numbers.
* @end deftypefun
@*/
int jit_insn_mark_offset(jit_function_t func, jit_int offset)
{
jit_block_t block;
jit_insn_t last;
jit_value_t value;
/* Ensure that we have a builder for this function */
if(!_jit_function_ensure_builder(func))
{
return 0;
}
value = jit_value_create_nint_constant(func, jit_type_int, offset);
if (!value)
{
return 0;
}
/* If the previous instruction is mark offset too
then just replace the offset value in place --
we are not interested in bytecodes that produce
no real code. */
block = func->builder->current_block;
last = _jit_block_get_last(block);
if (last && last->opcode == JIT_OP_MARK_OFFSET)
{
last->value1 = value;
return 1;
}
return create_unary_note(func, JIT_OP_MARK_OFFSET, value);
}
/* Documentation is in jit-debugger.c */
int jit_insn_mark_breakpoint_variable
(jit_function_t func, jit_value_t data1, jit_value_t data2)
{
#if defined(JIT_BACKEND_INTERP)
/* Use the "mark_breakpoint" instruction for the interpreter */
if(!jit_insn_new_block(func))
{
return 0;
}
return create_note(func, JIT_OP_MARK_BREAKPOINT, data1, data2);
#else
/* Insert a call to "_jit_debugger_hook" on native platforms */
( run in 0.717 second using v1.01-cache-2.11-cpan-e1769b4cff6 )