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(®s->descs[1], ®s->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 = ®s->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(®s->descs[1], ®s->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 = ®s->descs[1];
desc2 = ®s->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, ®s->descs[2], ®s->descs[1]);
if(regs->ternary)
{
check_duplicate_value(regs, ®s->descs[2], ®s->descs[0]);
}
}
if(regs->descs[1].value && regs->descs[1].reg >= 0)
{
if(regs->ternary)
{
check_duplicate_value(regs, ®s->descs[1], ®s->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, ®s->descs[0], ®s->descs[1]);
check_duplicate_value(regs, ®s->descs[0], ®s->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, ®s->descs[1], ®s->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 )