Alien-LibJIT

 view release on metacpan or  search on metacpan

libjit/jit/jit-block.c  view on Meta::CPAN

		{
			block->preds = 0;
		}
		else
		{
			block->preds = jit_calloc(block->num_preds, sizeof(_jit_edge_t));
			if(!block->preds)
			{
				jit_exception_builtin(JIT_RESULT_OUT_OF_MEMORY);
			}
			/* Reset edge count for the next build pass */
			block->num_preds = 0;
		}
	}
}

static void
detach_edge_src(_jit_edge_t edge)
{
	jit_block_t block;
	int index;

	block = edge->src;
	for(index = 0; index < block->num_succs; index++)
	{
		if(block->succs[index] == edge)
		{
			for(block->num_succs--; index < block->num_succs; index++)
			{
				block->succs[index] = block->succs[index + 1];
			}
			block->succs = jit_realloc(block->succs, block->num_succs * sizeof(_jit_edge_t));
			return;
		}
	}
}

static void
detach_edge_dst(_jit_edge_t edge)
{
	jit_block_t block;
	int index;

	block = edge->dst;
	for(index = 0; index < block->num_preds; index++)
	{
		if(block->preds[index] == edge)
		{
			for(block->num_preds--; index < block->num_preds; index++)
			{
				block->preds[index] = block->preds[index + 1];
			}
			block->preds = jit_realloc(block->preds,
						   block->num_preds * sizeof(_jit_edge_t));
			return;
		}
	}
}

static void
attach_edge_dst(_jit_edge_t edge, jit_block_t block)
{
	_jit_edge_t *preds;

	preds = jit_realloc(block->preds, (block->num_preds + 1) * sizeof(_jit_edge_t));
	if(!preds)
	{
		jit_exception_builtin(JIT_RESULT_OUT_OF_MEMORY);
	}

	preds[block->num_preds++] = edge;
	block->preds = preds;
	edge->dst = block;
}

/* Delete edge along with references to it */
static void
delete_edge(jit_function_t func, _jit_edge_t edge)
{
	detach_edge_src(edge);
	detach_edge_dst(edge);
	jit_memory_pool_dealloc(&func->builder->edge_pool, edge);
}

/* Block may not be deleted right when it was found useless from
   the control flow perspective as it might be referenced from
   elsewhere, for instance, from some jit_value_t */
static void
delete_block(jit_block_t block)
{
	jit_free(block->succs);
	block->succs = 0;
	jit_free(block->preds);
	block->preds = 0;
	jit_free(block->insns);
	block->insns = 0;

	block->next = block->func->builder->deleted_blocks;
	block->func->builder->deleted_blocks = block;
}

/* The block is empty if it contains nothing apart from an unconditional branch */
static int
is_empty_block(jit_block_t block)
{
	int index, opcode;

	index = block->num_insns;
	if(index == 0)
	{
		return 1;
	}

	opcode = block->insns[--index].opcode;
	if(opcode != JIT_OP_NOP && opcode != JIT_OP_MARK_OFFSET && opcode != JIT_OP_BR)
	{
		return 0;
	}

	while(index > 0)
	{

libjit/jit/jit-block.c  view on Meta::CPAN

merge_labels(jit_function_t func, jit_block_t src, jit_block_t dst)
{
	_jit_label_info_t *info;
	jit_label_t label, alias;

	label = src->label;
	src->label = jit_label_undefined;

#ifdef _JIT_BLOCK_DEBUG
	label_loop_check(func, dst, label);
#endif

	while(label != jit_label_undefined)
	{
		info = &func->builder->label_info[label];
		alias = info->alias;

		if((info->flags & JIT_LABEL_ADDRESS_OF) == 0)
		{
			info->block = dst;
			info->alias = dst->label;
			dst->label = label;
		}
		else
		{
			info->alias = src->label;
			src->label = label;
		}

		label = alias;
	}
}

/* Merge empty block with its successor */
static void
merge_empty(jit_function_t func, jit_block_t block, int *changed)
{
	_jit_edge_t succ_edge, pred_edge, fallthru_edge;
	jit_block_t succ_block;
	int index;

	/* Find block successor */
	succ_edge = block->succs[0];
	succ_block = succ_edge->dst;

	/* Retarget labels bound to this block to the successor block. */
	merge_labels(func, block, succ_block);

	/* Retarget all incoming edges except a fallthrough edge */
	fallthru_edge = 0;
	for(index = 0; index < block->num_preds; index++)
	{
		pred_edge = block->preds[index];
		if(pred_edge->flags == _JIT_EDGE_FALLTHRU)
		{
			fallthru_edge = pred_edge;
		}
		else
		{
			*changed = 1;
			attach_edge_dst(pred_edge, succ_block);
		}
	}

	/* Unless the block is taken address of, the incoming fallthrough edge
	   can be retargeted and then the block deleted if the outgoing edge is
	   also fallthrough. */
	if(!block->address_of && fallthru_edge && succ_edge->flags == _JIT_EDGE_FALLTHRU)
	{
		*changed = 1;
		attach_edge_dst(fallthru_edge, succ_block);
		fallthru_edge = 0;
	}

	/* Free the block if there is no incoming edge left and it is not taken
	   address of. Otherwise adjust the preds array accordingly.  */
	if(fallthru_edge)
	{
		if(block->num_preds > 1)
		{
			block->num_preds = 1;
			block->preds = jit_realloc(block->preds, sizeof(_jit_edge_t));
			block->preds[0] = fallthru_edge;
		}
	}
	else if(block->address_of)
	{
		if(block->num_preds > 0)
		{
			block->num_preds = 0;
			jit_free(block->preds);
			block->preds = 0;
		}
	}
	else
	{
		detach_edge_dst(succ_edge);
		jit_memory_pool_dealloc(&func->builder->edge_pool, succ_edge);
		_jit_block_detach(block, block);
		delete_block(block);
	}
}

/* Combine non-empty block with its successor */
static void
combine_block(jit_function_t func, jit_block_t block, int *changed)
{
	jit_block_t succ_block;
	int branch, num_insns, max_insns;
	jit_insn_t insns;

	/* Find block successor */
	succ_block = block->succs[0]->dst;

	/* Does block end with a (redundant) branch instruction? */
	branch = (block->succs[0]->flags == _JIT_EDGE_BRANCH);

	/* If the branch is there then preallocate memory for it,
	   doing it here simplifies handling of the out-of-memory
	   condition */
	if(branch && !succ_block->max_insns)
	{
		succ_block->insns = jit_malloc(sizeof(struct _jit_insn));
		if(!succ_block->insns)
		{
			jit_exception_builtin(JIT_RESULT_OUT_OF_MEMORY);
		}
		succ_block->max_insns = 1;
	}

	/* Allocate enough memory for combined instructions */

libjit/jit/jit-block.c  view on Meta::CPAN

				++top;
			}
		}
	}
	while(top);

	jit_free(stack);
	if(num < num_blocks)
	{
		blocks = jit_realloc(blocks, num * sizeof(jit_block_t));
	}

	func->builder->block_order = blocks;
	func->builder->num_block_order = num;
	return 1;
}

jit_block_t
_jit_block_create(jit_function_t func)
{
	jit_block_t block;

	/* Allocate memory for the block */
	block = jit_cnew(struct _jit_block);
	if(!block)
	{
		return 0;
	}

	/* Initialize the block */
	block->func = func;
	block->label = jit_label_undefined;

	return block;
}

void
_jit_block_destroy(jit_block_t block)
{
	/* Free all the memory owned by the block. CFG edges are not freed
	   because each edge is shared between two blocks so the ownership
	   of the edge is ambiguous. Sometimes an edge may be redirected to
	   another block rather than freed. Therefore edges are freed (or
	   not freed) separately. However succs and preds arrays are freed,
	   these contain pointers to edges, not edges themselves. */
	jit_meta_destroy(&block->meta);
	jit_free(block->succs);
	jit_free(block->preds);
	jit_free(block->insns);
	jit_free(block);
}

void
_jit_block_detach(jit_block_t first, jit_block_t last)
{
	last->next->prev = first->prev;
	first->prev->next = last->next;
}

void
_jit_block_attach_after(jit_block_t block, jit_block_t first, jit_block_t last)
{
	first->prev = block;
	last->next = block->next;
	block->next->prev = last;
	block->next = first;
}

void
_jit_block_attach_before(jit_block_t block, jit_block_t first, jit_block_t last)
{
	first->prev = block->prev;
	last->next = block;
	block->prev->next = first;
	block->prev = last;
}

/* Make space for the label in the label info table */
static int
ensure_label_table(jit_function_t func, jit_label_t label)
{
	jit_label_t num;
	_jit_label_info_t *info;

	if(label >= func->builder->max_label_info)
	{
		num = func->builder->max_label_info;
		if(num < 64)
		{
			num = 64;
		}
		while(num <= label)
		{
			num *= 2;
		}

		info = (_jit_label_info_t *) jit_realloc(func->builder->label_info,
							 num * sizeof(_jit_label_info_t));
		if(!info)
		{
			return 0;
		}

		jit_memzero(info + func->builder->max_label_info,
			    sizeof(_jit_label_info_t) * (num - func->builder->max_label_info));
		func->builder->label_info = info;
		func->builder->max_label_info = num;
	}

	return 1;
}

int
_jit_block_record_label(jit_block_t block, jit_label_t label)
{
	jit_builder_t builder;

	if(!ensure_label_table(block->func, label))
	{
		return 0;
	}

	builder = block->func->builder;

	/* Bail out on previously recorded label */
	if(builder->label_info[label].block)
	{
		return 0;
	}



( run in 1.021 second using v1.01-cache-2.11-cpan-e1769b4cff6 )