Alien-LibJIT

 view release on metacpan or  search on metacpan

libjit/jit/jit-reg-alloc.c  view on Meta::CPAN

					/* This depends on choose_input_order()
					   doing its job on the next step. */
					use_cost = 0;
				}
#ifdef JIT_REG_STACK
				else if(regs->reversible && regs->no_pop)
				{
					/* This depends on choose_input_order()
					   doing its job on the next step. */
					use_cost = 0;
				}
#endif
				else
				{
					use_cost = COST_THRASH;
				}
			}
			else
			{
				use_cost = COST_COPY;
			}
			if(regs->descs[0].value->has_global_register)
			{
				use_cost += COST_GLOBAL_BIAS;
			}
		}

		if(!jit_reg_is_used(regs->clobber, reg)
		   && !(other_reg >= 0 && jit_reg_is_used(regs->clobber, other_reg)))
		{
			use_cost += compute_spill_cost(gen, regs, reg, other_reg);
		}

#ifdef JIT_REG_DEBUG
		printf("reg = %d, other_reg = %d, use_cost = %d\n", reg, other_reg, use_cost);
#endif

		if(use_cost < suitable_cost
		   || (use_cost == suitable_cost
		       && gen->contents[reg].num_values > 0
		       && gen->contents[reg].age < suitable_age))
		{
			suitable_reg = reg;
			suitable_other_reg = other_reg;
			suitable_cost = use_cost;
			suitable_age = gen->contents[reg].age;
		}
	}

	if(suitable_reg >= 0)
	{
		set_regdesc_register(gen, regs, 0, suitable_reg, suitable_other_reg);
	}
	else
	{
		jit_exception_builtin(JIT_RESULT_COMPILE_ERROR);
	}
}

/*
 * Select the best argument order for binary ops. The posibility to select
 * the order exists only for commutative ops and for some x87 floating point
 * instructions. Those x87 instructions have variants with reversed
 * destination register.
 */
static void
choose_input_order(jit_gencode_t gen, _jit_regs_t *regs)
{
	jit_value_t value;

	value = regs->descs[2].value;
	if(value && value != regs->descs[1].value
	   && ((value->in_register
		&& value->reg == regs->descs[0].reg)
	       || (value->in_global_register
		   && value->global_reg == regs->descs[0].reg)))
	{
#ifdef JIT_REG_STACK
		if(regs->reversible && regs->no_pop)
		{
			regs->dest_input_index = 2;
		}
		else
#endif
		{
			if(regs->commutative)
			{
				swap_values(&regs->descs[1], &regs->descs[2]);
			}
			regs->dest_input_index = 1;
		}
	}
	else if(regs->descs[1].value)
	{
		regs->dest_input_index = 1;
	}
	else
	{
		regs->dest_input_index = 0;
	}
}

static void
choose_input_register(jit_gencode_t gen, _jit_regs_t *regs, int index)
{
	_jit_regclass_t *regclass;
	_jit_regdesc_t *desc;
	_jit_regdesc_t *desc2;
	int reg_index, reg, other_reg;
	int use_cost;
	int suitable_reg, suitable_other_reg;
	int suitable_cost;
	int suitable_age;
	int clobber;

#ifdef JIT_REG_DEBUG
	printf("choose_input_register(%d)\n", index);
#endif

	desc = &regs->descs[index];
	if(!desc->value)

libjit/jit/jit-reg-alloc.c  view on Meta::CPAN

			   && !(other_reg >= 0 && jit_reg_is_used(regs->clobber, other_reg)))
			{
				use_cost += compute_spill_cost(gen, regs, reg, other_reg);
			}
		}

#ifdef JIT_REG_DEBUG
		printf("reg = %d, other_reg = %d, use_cost = %d\n", reg, other_reg, use_cost);
#endif

		if(use_cost < suitable_cost
		   || (use_cost == suitable_cost
		       && gen->contents[reg].num_values > 0
		       && gen->contents[reg].age < suitable_age))
		{
			/* This is the oldest suitable register of this type */
			suitable_reg = reg;
			suitable_other_reg = other_reg;
			suitable_cost = use_cost;
			suitable_age = gen->contents[reg].age;
		}
	}

	if(suitable_reg >= 0)
	{
		set_regdesc_register(gen, regs, index, suitable_reg, suitable_other_reg);
	}
	else
	{
		jit_exception_builtin(JIT_RESULT_COMPILE_ERROR);
	}
}

/*
 * Assign diplicate input value to the same register if possible.
 * The first value has to be already assigned. The second value
 * is assigned to the same register if it is equal to the first
 * and neither of them is clobbered.
 */
static void
check_duplicate_value(_jit_regs_t *regs, _jit_regdesc_t *desc1, _jit_regdesc_t *desc2)
{
	if(desc2->reg < 0 && desc1->reg >= 0 && are_values_equal(desc1, desc2)
#ifdef JIT_REG_STACK
	   && (!IS_STACK_REG(desc1->reg) || regs->x87_arith)
#endif
	   && !desc1->early_clobber && !desc2->early_clobber)
	{
		desc2->reg = desc1->reg;
		desc2->other_reg = desc1->other_reg;
		desc2->duplicate = 1;
	}
}

#ifdef JIT_REG_STACK

/*
 * For x87 instructions choose between pop and no-pop variants.
 */
static void
select_nopop_or_pop(jit_gencode_t gen, _jit_regs_t *regs)
{
	int keep1, keep2;

	if(!regs->x87_arith || !regs->descs[1].value || !regs->descs[2].value)
	{
		return;
	}

	/* Equal values should be assigned to one register and this is
	   going to work only with no-pop instructions. */
	if(are_values_equal(&regs->descs[1], &regs->descs[2]))
	{
		regs->no_pop = 1;
		return;
	}

	/* Determine if we might want to keep input values in registers
	   after the instruction completion. */
	if(regs->descs[1].value->in_register)
	{
		keep1 = is_register_alive(gen, regs, regs->descs[1].value->reg);
	}
	else
	{
		keep1 = (regs->descs[1].used
			 && (regs->descs[1].value != regs->descs[0].value)
			 && !regs->descs[1].clobber);
	}
	if(regs->descs[2].value->in_register)
	{
		keep2 = is_register_alive(gen, regs, regs->descs[2].value->reg);
	}
	else
	{
		keep2 = (regs->descs[2].used
			 && (regs->descs[2].value != regs->descs[0].value)
			 && !regs->descs[2].clobber);
	}

	regs->no_pop = (keep1 || keep2);
}

static void
select_stack_order(jit_gencode_t gen, _jit_regs_t *regs)
{
	_jit_regdesc_t *desc1;
	_jit_regdesc_t *desc2;
	int top_index;

#ifdef JIT_REG_DEBUG
	printf("select_stack_order()\n");
#endif

	if(!regs->x87_arith || regs->wanted_stack_count != 2)
	{
		return;
	}

	desc1 = &regs->descs[1];
	desc2 = &regs->descs[2];

	/* Choose instruction that results into fewer exchanges. If either
	   of two arguments may be on the stack top choose the second to be
	   on top. */
	/* TODO: See if the next instruction wants the output or remaining
	   input to be on the stack top. */
 	if(desc2->copy || desc2->load)
	{
		/* the second argument is going to be on the top */
		top_index = 2;
	}
	else if(desc1->copy || desc1->load)
	{
		/* the first argument is going to be on the top */
		top_index = 1;
	}
	else if(desc2->value->reg == (gen->reg_stack_top - 1))
	{
		/* the second argument is already on the top */
		top_index = 2;
	}
	else if(desc1->value->reg == (gen->reg_stack_top - 1))
	{
		/* the first argument is already on the top */
		top_index = 1;
	}
	else
	{
		top_index = 2;
	}

	if(regs->no_pop)
	{
		regs->flip_args = (top_index == 2);
	}
	else if(regs->reversible)
	{
		if(top_index == 2)
		{
			regs->flip_args = 1;
			regs->dest_input_index = 1;
		}
		else
		{
			regs->flip_args = 0;
			regs->dest_input_index = 2;
		}
	}
	else /*if(regs->commutative)*/
	{
		regs->flip_args = 1;

libjit/jit/jit-reg-alloc.c  view on Meta::CPAN

		jit_reg_set_used(regs->clobber, regclass->regs[index]);
	}
}

void
_jit_regs_clobber_all(jit_gencode_t gen, _jit_regs_t *regs)
{
	int index;

	for(index = 0; index < JIT_NUM_REGS; index++)
	{
		if((jit_reg_flags(index) & JIT_REG_FIXED) != 0)
		{
			continue;
		}
		if(jit_reg_is_used(gen->permanent, index))
		{
			continue;
		}
		jit_reg_set_used(regs->clobber, index);
	}
}

void
_jit_regs_assign(jit_gencode_t gen, _jit_regs_t *regs)
{
	int index;

#ifdef JIT_REG_DEBUG
	printf("_jit_regs_assign()\n");
#endif

	/* Check explicitely assigned registers */
	if(regs->descs[2].value && regs->descs[2].reg >= 0)
	{
		check_duplicate_value(regs, &regs->descs[2], &regs->descs[1]);
		if(regs->ternary)
		{
			check_duplicate_value(regs, &regs->descs[2], &regs->descs[0]);
		}
	}
	if(regs->descs[1].value && regs->descs[1].reg >= 0)
	{
		if(regs->ternary)
		{
			check_duplicate_value(regs, &regs->descs[1], &regs->descs[0]);
		}
		else if(!regs->free_dest && regs->descs[0].value && regs->descs[0].reg < 0)
		{
			/* For binary or unary ops with explicitely assigned registers
			   the output always goes to the same register as the first input
			   value unless this is a three-address instruction. */
			set_regdesc_register(gen, regs, 0,
					     regs->descs[1].reg,
					     regs->descs[1].other_reg);
		}
	}

#if JIT_REG_STACK
	/* Choose between x87 pop and no-pop instructions.  */
	select_nopop_or_pop(gen, regs);
#endif

	/* Assign output and input registers. */
	if(regs->descs[0].value)
	{
		if(regs->descs[0].reg < 0)
		{
			if(regs->ternary)
			{
				choose_input_register(gen, regs, 0);
			}
			else
			{
				choose_output_register(gen, regs);
			}
		}
		if(regs->ternary)
		{
			check_duplicate_value(regs, &regs->descs[0], &regs->descs[1]);
			check_duplicate_value(regs, &regs->descs[0], &regs->descs[2]);
		}
		else if(!regs->free_dest)
		{
			choose_input_order(gen, regs);
			if(regs->dest_input_index)
			{
				set_regdesc_register(gen, regs, regs->dest_input_index,
						     regs->descs[0].reg,
						     regs->descs[0].other_reg);
			}
		}
	}
	if(regs->descs[1].value && regs->descs[1].reg < 0)
	{
		choose_input_register(gen, regs, 1);
	}
	check_duplicate_value(regs, &regs->descs[1], &regs->descs[2]);
	if(regs->descs[2].value && regs->descs[2].reg < 0)
	{
		choose_input_register(gen, regs, 2);
	}

	/* Assign scratch registers. */
	for(index = 0; index < regs->num_scratch; index++)
	{
		if(regs->scratch[index].reg < 0)
		{
			choose_scratch_register(gen, regs, index);
		}
	}

	/* Collect information about registers. */
	set_regdesc_flags(gen, regs, 0);
	set_regdesc_flags(gen, regs, 1);
	set_regdesc_flags(gen, regs, 2);
}

void
_jit_regs_gen(jit_gencode_t gen, _jit_regs_t *regs)
{

libjit/jit/jit-reg-alloc.c  view on Meta::CPAN

#ifdef JIT_REG_DEBUG
			printf("*** Spill global register: %d ***\n", reg);
#endif
			if(regs->branch)
			{
				/* After the branch is taken there is no way
				   to load the global register back. */
				jit_exception_builtin(JIT_RESULT_COMPILE_ERROR);
			}
			_jit_gen_spill_global(gen, reg, 0);
			continue;
		}

#ifdef JIT_REG_STACK
		/* If this is a stack register, then we need to find the
		   register that contains the top-most stack position,
		   because we must spill stack registers from top down.
		   As we spill each one, something else will become the top */
		if(IS_STACK_REG(reg))
		{
			int top = gen->reg_stack_top - 1;
			/* spill top registers if there are any that needs to be */
			for(; top >= reg && jit_reg_is_used(regs->clobber, top); top--)
			{
				spill_clobbered_register(gen, regs, top);
				/* If an input value is on the top then it stays there
				   and the top position does not change. */
				if(gen->contents[top].num_values > 0)
				{
					break;
				}
			}
			if(top > reg)
			{
				spill_clobbered_register(gen, regs, reg);
			}
		}
		else
#endif
		{
			spill_clobbered_register(gen, regs, reg);
		}
	}

	/* Save input values if necessary and free the output value if it is in a register */
	if(regs->ternary)
	{
		save_input_value(gen, regs, 0);
	}
	else
	{
		free_output_value(gen, regs);
	}
	save_input_value(gen, regs, 1);
	save_input_value(gen, regs, 2);

#ifdef JIT_REG_STACK
	if(regs->wanted_stack_count > 0)
	{
		/* Adjust assignment of stack registers. */
		select_stack_order(gen, regs);
		adjust_assignment(gen, regs, 2);
		adjust_assignment(gen, regs, 1);
		adjust_assignment(gen, regs, 0);

		if(regs->ternary)
		{
			/* Ternary ops with only one stack register are supported. */
			if(regs->loaded_stack_count > 0)
			{
				move_input_value(gen, regs, 0);
				move_input_value(gen, regs, 1);
				move_input_value(gen, regs, 2);
			}
			load_input_value(gen, regs, 0);
			load_input_value(gen, regs, 1);
			load_input_value(gen, regs, 2);
		}
		else if(regs->flip_args)
		{
			/* Shuffle the values that are already on the register stack. */
			if(regs->loaded_stack_count > 0)
			{
				move_input_value(gen, regs, 1);
				move_input_value(gen, regs, 2);
			}

			/* Load and shuffle the remaining values. */
			load_input_value(gen, regs, 1);
			move_input_value(gen, regs, 1);
			load_input_value(gen, regs, 2);
		}
		else
		{
			/* Shuffle the values that are already on the register stack. */
			if(regs->loaded_stack_count > 0)
			{
				move_input_value(gen, regs, 2);
				move_input_value(gen, regs, 1);
			}

			/* Load and shuffle the remaining values. */
			load_input_value(gen, regs, 2);
			move_input_value(gen, regs, 2);
			load_input_value(gen, regs, 1);
		}
	}
	else
#endif
	{
		/* Load flat registers. */
		if(regs->ternary)
		{
			load_input_value(gen, regs, 0);
		}
#ifdef JIT_REG_STACK
		else if(regs->descs[0].reg >= 0 && IS_STACK_REG(regs->descs[0].reg))
		{
			adjust_assignment(gen, regs, 0);
		}
#endif
		load_input_value(gen, regs, 1);
		load_input_value(gen, regs, 2);
	}

#ifdef JIT_REG_DEBUG
	dump_regs(gen, "leave _jit_regs_gen");
#endif
}

#ifdef JIT_REG_STACK
int
_jit_regs_select(_jit_regs_t *regs)
{
	int flags;

	flags = 0;
	if(regs->no_pop)
	{
		flags |= _JIT_REGS_NO_POP;
	}
	if(regs->flip_args)
	{
		flags |= _JIT_REGS_FLIP_ARGS;
	}
	if(regs->dest_input_index == 2)
	{
		flags |= _JIT_REGS_REVERSE;
	}
	return flags;
}
#endif

void
_jit_regs_commit(jit_gencode_t gen, _jit_regs_t *regs)
{
	int reg;

#ifdef JIT_REG_DEBUG
	dump_regs(gen, "enter _jit_regs_commit");
#endif

	if(regs->ternary)
	{
#ifdef JIT_REG_STACK
		if(regs->wanted_stack_count > 0)
		{
			pop_input_value(gen, regs, 0);
			pop_input_value(gen, regs, 1);
			pop_input_value(gen, regs, 2);
		}
#endif
		commit_input_value(gen, regs, 0, 1);
		commit_input_value(gen, regs, 1, 1);
		commit_input_value(gen, regs, 2, 1);
	}
	else if(!regs->descs[0].value)
	{
#ifdef JIT_REG_STACK
		if(regs->wanted_stack_count > 0)
		{
			pop_input_value(gen, regs, 1);
			pop_input_value(gen, regs, 2);
		}
#endif
		commit_input_value(gen, regs, 1, 1);
		commit_input_value(gen, regs, 2, 1);
	}
#ifdef JIT_REG_STACK
	else if(regs->wanted_stack_count > 0)
	{
		int pop1, pop2;
		struct _jit_value temp;



( run in 0.351 second using v1.01-cache-2.11-cpan-fa01517f264 )