return 0;
}
+static void
+swap_values(_jit_regdesc_t *desc1, _jit_regdesc_t *desc2)
+{
+ _jit_regdesc_t tdesc;
+ tdesc = *desc1;
+ *desc1 = *desc2;
+ *desc2 = tdesc;
+}
/*
* Get value usage and liveness information. The accurate liveness data is
}
}
}
+
+ if(gen->contents[reg].is_long_start)
+ {
+ return cost * 2;
+ }
+
if(other_reg >= 0)
{
for(index = 0; index < gen->contents[other_reg].num_values; index++)
}
}
}
+
return cost;
}
int suitable_cost;
int suitable_age;
+#ifdef JIT_REG_DEBUG
+ printf("choose_scratch_register(%d)\n", index);
+#endif
+
regclass = regs->scratch[index].regclass;
suitable_reg = -1;
continue;
}
-#if ALLOW_CLOBBER_GLOBAL
if(jit_reg_is_used(gen->permanent, reg))
{
+#if ALLOW_CLOBBER_GLOBAL
use_cost = COST_CLOBBER_GLOBAL;
+#else
+ continue;
+#endif
}
else
{
use_cost = 0;
}
-#else
- if(jit_reg_is_used(gen->permanent, reg))
- {
- continue;
- }
- use_cost = 0;
-#endif
+#if 0
if(regs->ternary && regs->descs[0].value
&& thrashes_value(gen, 0, reg, -1, ®s->descs[0]))
{
{
use_cost += COST_THRASH;
}
+#endif
- use_cost += compute_spill_cost(gen, regs, reg, -1);
+ if(!jit_reg_is_used(regs->clobber, reg))
+ {
+ use_cost += compute_spill_cost(gen, regs, reg, -1);
+ }
+
+#ifdef JIT_REG_DEBUG
+ printf("reg = %d, use_cost = %d\n", 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))
+ && (IS_STACK_REG(reg)
+ || gen->contents[reg].age < suitable_age)))
{
suitable_reg = reg;
suitable_cost = use_cost;
int suitable_cost;
int suitable_age;
+#ifdef JIT_REG_DEBUG
+ printf("choose_output_register()\n");
+#endif
+
regclass = regs->descs[0].regclass;
need_pair = _jit_regs_needs_long_pair(regs->descs[0].value->type);
use_cost = 0;
}
#ifdef JIT_REG_STACK
- else if(regs->x87_arith)
+ else if(regs->reversible && regs->no_pop)
{
use_cost = 0;
}
}
}
- use_cost += compute_spill_cost(gen, regs, reg, other_reg);
+ 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
/*
* 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 argument
- * order or reversed destination register. Also they have variants that
- * either do or do not pop the stack top.
+ * instructions. Those x87 instructions have variants with reversed
+ * destination register.
*/
static void
choose_input_order(jit_gencode_t gen, _jit_regs_t *regs)
{
- _jit_regdesc_t temp_desc;
-
if(regs->descs[2].value
&& regs->descs[2].value->in_register
&& regs->descs[2].value->reg == regs->descs[0].reg
&& regs->descs[2].value != regs->descs[1].value)
{
#ifdef JIT_REG_STACK
- if(regs->x87_arith)
+ if(regs->reversible && regs->no_pop)
{
- regs->no_pop = 1;
- regs->reverse_dest = 1;
regs->dest_input_index = 2;
}
else
{
if(regs->commutative)
{
- temp_desc = regs->descs[1];
- regs->descs[1] = regs->descs[2];
- regs->descs[2] = temp_desc;
+ swap_values(®s->descs[1], ®s->descs[2]);
}
regs->dest_input_index = 1;
}
{
regs->dest_input_index = 0;
}
-
-#ifdef JIT_REG_STACK
- /* Choose between pop and no-pop instructions. */
- if(!regs->no_pop && regs->x87_arith
- && !regs->clobber_all && !regs->clobber_stack
- && regs->descs[1].value && regs->descs[2].value)
- {
- int keep1, keep2;
-
- /* Determine if we might want to keep either of 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);
- }
-#endif
}
static int
int suitable_age;
int clobber;
+#ifdef JIT_REG_DEBUG
+ printf("choose_input_register(%d)\n", index);
+#endif
+
desc = ®s->descs[index];
if(!desc->value)
{
continue;
#endif
}
- if(jit_reg_is_used(regs->clobber, reg)
- || (other_reg >= 0 && jit_reg_is_used(regs->clobber, other_reg)))
- {
- /* noop */
- }
- else
+ 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
}
#ifdef JIT_REG_STACK
+
+/*
+ * For x87 instructions choose between pop and no-pop variants.
+ */
static void
-adjust_assignment(jit_gencode_t gen, _jit_regs_t *regs, int index)
+select_nopop_or_pop(jit_gencode_t gen, _jit_regs_t *regs)
{
- _jit_regdesc_t *desc;
+ int keep1, keep2;
- desc = ®s->descs[index];
- if(!desc->value || !IS_STACK_REG(desc->reg))
+ if(!regs->x87_arith || !regs->descs[1].value || !regs->descs[2].value)
{
return;
}
- if(regs->wanted_stack_count == 1)
+ /* 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]))
{
- /* either a unary op or a binary op with duplicate value */
- desc->reg = gen->reg_stack_top - regs->loaded_stack_count;
+ regs->no_pop = 1;
+ return;
}
- else if(regs->wanted_stack_count == 2)
+
+ /* Determine if we might want to keep input values in registers
+ after the instruction completion. */
+ if(regs->descs[1].value->in_register)
{
- /* a binary op */
+ 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);
+ }
- /* find the input value the output goes to */
- if(index == 0)
- {
- index = regs->dest_input_index;
- }
+ 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;
+ }
- if(desc->value->in_register && !desc->copy && regs->x87_arith)
+ 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)
{
- desc->reg = desc->value->reg;
+ regs->flip_args = 1;
+ regs->dest_input_index = 1;
}
else
{
- desc->reg = gen->reg_stack_top - regs->loaded_stack_count + index - 1;
+ regs->flip_args = 0;
+ regs->dest_input_index = 2;
}
}
-}
+ else /*if(regs->commutative)*/
+ {
+ regs->flip_args = 1;
+ regs->dest_input_index = 1;
+
+ if(top_index != 2)
+ {
+ swap_values(®s->descs[1], ®s->descs[2]);
+ }
+ }
+
+#ifdef JIT_REG_DEBUG
+ printf("top_index = %d, flip_args = %d, dest_input_index = %d\n",
+ top_index, regs->flip_args, regs->dest_input_index);
#endif
+}
-#ifdef JIT_REG_STACK
static void
-select_stack_order(jit_gencode_t gen, _jit_regs_t *regs)
+adjust_assignment(jit_gencode_t gen, _jit_regs_t *regs, int index)
{
- _jit_regdesc_t *desc1;
- _jit_regdesc_t *desc2;
- _jit_regdesc_t temp_desc;
- int top_index;
+ _jit_regdesc_t *desc, *desc2;
+
+#ifdef JIT_REG_DEBUG
+ printf("adjust_assignment(%d)\n", index);
+#endif
- /* Choose instruction that results into fewer exchanges. */
- if(regs->wanted_stack_count > 1 && regs->no_pop
- && (regs->commutative || regs->reversible))
+ desc = ®s->descs[index];
+ if(!desc->value || !IS_STACK_REG(desc->reg))
{
- desc1 = ®s->descs[1];
- desc2 = ®s->descs[2];
+ return;
+ }
- if(desc1->value->in_register && !desc1->copy
- && desc2->value->in_register && !desc2->copy)
+ if(regs->wanted_stack_count == 1)
+ {
+ /* either a unary op or a binary op with duplicate value */
+ desc->reg = gen->reg_stack_top - regs->loaded_stack_count;
+ }
+ else if(regs->wanted_stack_count == 2)
+ {
+ /* a binary op */
+
+ /* find the input value the output goes to */
+ if(index == 0)
{
- /* Is any of the input values on the stack top? */
- if(desc1->value->reg == (gen->reg_stack_top - 1))
+ if(regs->x87_arith)
{
- top_index = 1;
- }
- else if(desc2->value->reg == (gen->reg_stack_top - 1))
- {
- top_index = 2;
+ index = regs->dest_input_index;
}
else
{
- /* TODO: See if the next instruction wants output
- or remaining input to be on the stack top. */
- top_index = 2;
+ index = 2;
}
+ desc2 = ®s->descs[index];
}
- else if(desc1->value->in_register && !desc1->copy)
+ else
{
- top_index = 2;
+ desc2 = desc;
}
- else if(desc2->value->in_register && !desc2->copy)
+
+ if(regs->flip_args)
{
- top_index = 1;
+ if(regs->x87_arith && index == 1
+ && desc2->value->in_register && !desc2->copy)
+ {
+ desc->reg = desc2->value->reg;
+ }
+ else
+ {
+ desc->reg = (gen->reg_stack_top
+ - regs->loaded_stack_count
+ + index - 1);
+ }
}
else
{
- /* TODO: see if the next instruction wants output or remaining
- input to be on the stack top. */
- top_index = 2;
- }
-
- if(top_index == 1)
- {
- if(regs->reversible)
+ if(regs->x87_arith && index == 2
+ && desc2->value->in_register && !desc2->copy)
{
- regs->reverse_args = 1;
+ desc->reg = desc2->value->reg;
}
- else /*if(regs->commutative)*/
+ else
{
- temp_desc = *desc1;
- *desc1 = *desc2;
- *desc2 = temp_desc;
+ desc->reg = (gen->reg_stack_top
+ - regs->loaded_stack_count
+ + regs->wanted_stack_count
+ - index);
}
- regs->reverse_dest ^= 1;
}
}
+
+#ifdef JIT_REG_DEBUG
+ printf("reg = %d\n", desc->reg);
+#endif
}
+
#endif
/*
}
}
+#ifdef JIT_REG_STACK
static void
-commit_input_value(jit_gencode_t gen, _jit_regs_t *regs, int index, int go_down_stack)
+pop_input_value(jit_gencode_t gen, _jit_regs_t *regs, int index)
{
_jit_regdesc_t *desc;
- int reg, other_reg;
-#ifdef JIT_REG_STACK
- int is_down_stack = 0;
+
+#ifdef JIT_REG_DEBUG
+ printf("pop_input_value(%d)\n", index);
#endif
+ desc = ®s->descs[index];
+ if(!desc->value || desc->duplicate)
+ {
+ return;
+ }
+
+ if(IS_STACK_REG(desc->reg))
+ {
+ if(desc->copy)
+ {
+ gen->contents[desc->reg].used_for_temp = 0;
+ }
+ else
+ {
+ unbind_value(gen, desc->value, desc->reg, 0);
+ }
+ --(gen->reg_stack_top);
+ }
+}
+#endif
+
+static void
+commit_input_value(jit_gencode_t gen, _jit_regs_t *regs, int index, int killed)
+{
+ _jit_regdesc_t *desc;
+ int reg, other_reg;
+
#ifdef JIT_REG_DEBUG
- printf("commit_input_value(%d, %d)\n", index, go_down_stack);
+ printf("commit_input_value(%d)\n", index);
#endif
desc = ®s->descs[index];
return;
}
+#ifdef JIT_REG_STACK
+ if(!IS_STACK_REG(desc->reg))
+ {
+ killed = 0;
+ }
+#endif
+
if(desc->copy)
{
#ifdef JIT_REG_STACK
- if(IS_STACK_REG(desc->reg))
+ if(killed)
{
- if(!go_down_stack)
- {
- if(1/*!regs->copy*/)
- {
- --(gen->reg_stack_top);
- }
- gen->contents[desc->reg].used_for_temp = 0;
- }
- is_down_stack = 1;
+ killed = 0;
}
else
#endif
}
#ifdef JIT_REG_STACK
- if(desc->kill && desc->value->in_register && is_down_stack == go_down_stack)
+ if(!killed && desc->kill && desc->value->in_register)
#else
if(desc->kill && desc->value->in_register)
#endif
{
other_reg = -1;
}
-#ifdef JIT_REG_STACK
- if(is_down_stack)
- {
- free_value(gen, desc->value, reg, other_reg, 0);
- }
- else
- {
- unbind_value(gen, desc->value, reg, other_reg);
- if(IS_STACK_REG(reg) /*&& !regs->copy*/)
- {
- --(gen->reg_stack_top);
- }
- }
-#else
- unbind_value(gen, desc->value, reg, other_reg);
-#endif
+ free_value(gen, desc->value, reg, other_reg, 0);
}
#ifdef JIT_REG_DEBUG
}
static void
-commit_output_value(jit_gencode_t gen, _jit_regs_t *regs)
+commit_output_value(jit_gencode_t gen, _jit_regs_t *regs, int push_stack_top)
{
_jit_regdesc_t *desc;
return;
}
-#ifdef JIT_REG_STACK
- if(IS_STACK_REG(desc->reg) /*&& !regs->copy*/)
+ if(IS_STACK_REG(desc->reg) && push_stack_top)
{
++(gen->reg_stack_top);
}
-#endif
bind_value(gen, desc->value, desc->reg, desc->other_reg, 0);
if(!desc->used)
{
int index;
-#ifdef JIT_REG_STACK
- if((regclass->flags & JIT_REG_IN_STACK) != 0)
- {
- regs->clobber_stack = 1;
- }
-#endif
-
for(index = 0; index < regclass->num_regs; index++)
{
if(jit_reg_is_used(gen->permanent, index))
{
int index;
- regs->clobber_all = 1;
-
for(index = 0; index < JIT_NUM_REGS; index++)
{
if((_jit_reg_info[index].flags & JIT_REG_FIXED) != 0)
the output always goes to the same register as the first input
value unless this is a three-address instruction. */
if(!regs->ternary && !regs->free_dest
- && regs->descs[0].value
- && regs->descs[1].value)
+ && regs->descs[0].value && regs->descs[0].reg < 0
+ && regs->descs[1].value && regs->descs[1].reg >= 0)
{
- if(regs->descs[0].reg >= 0)
- {
- if(regs->descs[1].reg < 0)
- {
- set_regdesc_register(gen, regs, 1,
- regs->descs[0].reg,
- regs->descs[0].other_reg);
- }
- }
- else if(regs->descs[1].reg >= 0)
- {
- set_regdesc_register(gen, regs, 0,
- regs->descs[1].reg,
- regs->descs[1].other_reg);
- }
+ 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 && regs->descs[0].reg < 0)
+ if(regs->descs[0].value)
{
- if(regs->ternary)
+ if(regs->descs[0].reg < 0)
{
- if(!choose_input_register(gen, regs, 0))
+ if(regs->ternary)
{
- return 0;
+ if(!choose_input_register(gen, regs, 0))
+ {
+ return 0;
+ }
+ }
+ else
+ {
+ if(!choose_output_register(gen, regs))
+ {
+ return 0;
+ }
}
+ }
+ if(regs->ternary)
+ {
check_duplicate_value(regs, ®s->descs[0], ®s->descs[1]);
check_duplicate_value(regs, ®s->descs[0], ®s->descs[2]);
}
- else
+ else if(!regs->free_dest)
{
- if(!choose_output_register(gen, regs))
+ choose_input_order(gen, regs);
+ if(regs->dest_input_index)
{
- return 0;
- }
- 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);
- }
+ set_regdesc_register(gen, regs, regs->dest_input_index,
+ regs->descs[0].reg,
+ regs->descs[0].other_reg);
}
}
}
if(regs->wanted_stack_count > 0)
{
/* Adjust assignment of stack registers. */
- adjust_assignment(gen, regs, 0);
- adjust_assignment(gen, regs, 1);
- adjust_assignment(gen, regs, 2);
-
select_stack_order(gen, regs);
+ adjust_assignment(gen, regs, 2);
+ adjust_assignment(gen, regs, 1);
+ adjust_assignment(gen, regs, 0);
- /* Shuffle the values that are already on the register stack. */
- if(regs->loaded_stack_count > 0 && !regs->x87_arith)
+ if(regs->ternary)
{
- move_input_value(gen, regs, 1);
- move_input_value(gen, regs, 2);
+ /* 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);
+ }
+ else
+ {
+ load_input_value(gen, regs, 0);
+ load_input_value(gen, regs, 1);
+ load_input_value(gen, regs, 2);
+ }
}
-
- /* Load and shuffle the remaining values. */
- if(regs->reverse_args)
+ else if(regs->flip_args)
{
- load_input_value(gen, regs, 2);
- move_input_value(gen, regs, 2);
+ /* 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
{
- if(regs->ternary)
+ /* Shuffle the values that are already on the register stack. */
+ if(regs->loaded_stack_count > 0)
{
- load_input_value(gen, regs, 0);
- move_input_value(gen, regs, 0);
+ move_input_value(gen, regs, 2);
+ move_input_value(gen, regs, 1);
}
- load_input_value(gen, regs, 1);
- 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
{
flags |= _JIT_REGS_NO_POP;
}
- if(regs->reverse_dest)
+ if(regs->flip_args)
{
- flags |= _JIT_REGS_REVERSE_DEST;
+ flags |= _JIT_REGS_FLIP_ARGS;
}
- if(regs->reverse_args)
+ if(regs->dest_input_index == 2)
{
- flags |= _JIT_REGS_REVERSE_ARGS;
+ flags |= _JIT_REGS_REVERSE;
}
-
return flags;
}
#endif
dump_regs(gen, "enter _jit_regs_commit");
#endif
-#ifdef JIT_REG_STACK
- if(regs->wanted_stack_count > 0)
+ if(regs->ternary)
{
- int reg1, reg2;
-
- /* The stack registers has to be freed from the top down. It is
- assumed that only binary instructions may have more than one
- stack register. The unary instruction may not do that for
- obvious reasons. The practical observation is that no ternary
- instruction in libjit does that as well. */
- if(regs->reverse_args)
+#ifdef JIT_REG_STACK
+ if(regs->wanted_stack_count > 0)
{
- commit_input_value(gen, regs, 1, 0);
- commit_input_value(gen, regs, 2, 0);
+ pop_input_value(gen, regs, 0);
+ pop_input_value(gen, regs, 1);
+ pop_input_value(gen, regs, 2);
}
- else
+#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)
{
- commit_input_value(gen, regs, 2, 0);
- commit_input_value(gen, regs, 1, 0);
+ pop_input_value(gen, regs, 1);
+ pop_input_value(gen, regs, 2);
}
- if(regs->ternary)
+#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;
+ int reg1, reg2;
+
+ pop1 = pop2 = 0;
+ if(!regs->no_pop)
{
- commit_input_value(gen, regs, 0, 0);
+ if(regs->x87_arith)
+ {
+ if(regs->flip_args)
+ {
+ pop_input_value(gen, regs, 2);
+ pop2 = 1;
+ }
+ else
+ {
+ pop_input_value(gen, regs, 1);
+ pop1 = 1;
+ }
+ }
+ else
+ {
+ pop_input_value(gen, regs, 1);
+ pop_input_value(gen, regs, 2);
+ pop1 = pop2 = 1;
+ }
}
- else
+
+ if(IS_STACK_REG(regs->descs[0].reg))
{
- commit_output_value(gen, regs);
+ temp = *regs->descs[0].value;
+ if(!regs->x87_arith && !regs->copy)
+ {
+ ++(gen->reg_stack_top);
+ }
+ bind_value(gen, &temp, regs->descs[0].reg, -1, 0);
}
- /* If the allocator makes a copy of a value that was already on
- the stack we might need to free the original register as well.
- In general, the allocator makes a copy if the value is going
- to be destroyed by the instruction while it is still used
- (according to the liveness analysis). But the original value
- needs to be freed only if it is no longer used. So this extra
- code seems useless. But there were cases when the allocator
- miscalculated the cost of spilling and made a copy when it
- was not needed. So this code serves as a precaution against
- such problematic cases. */
reg1 = ((regs->descs[1].value && regs->descs[1].value->in_register)
? regs->descs[1].value->reg : -1);
reg2 = ((regs->descs[2].value && regs->descs[2].value->in_register)
? regs->descs[2].value->reg : -1);
if(reg1 > reg2)
{
- commit_input_value(gen, regs, 1, 1);
- commit_input_value(gen, regs, 2, 1);
+ commit_input_value(gen, regs, 1, pop1);
+ commit_input_value(gen, regs, 2, pop2);
}
else
{
- commit_input_value(gen, regs, 2, 1);
- commit_input_value(gen, regs, 1, 1);
+ commit_input_value(gen, regs, 2, pop2);
+ commit_input_value(gen, regs, 1, pop1);
}
+
+ if(IS_STACK_REG(regs->descs[0].reg))
+ {
+ reg1 = temp.reg;
+ free_value(gen, &temp, reg1, -1, 1);
+ regs->descs[0].reg = reg1;
+ regs->descs[0].other_reg = -1;
+ }
+ commit_output_value(gen, regs, 0);
}
else
#endif
{
commit_input_value(gen, regs, 2, 0);
commit_input_value(gen, regs, 1, 0);
- if(regs->ternary)
- {
- commit_input_value(gen, regs, 0, 0);
- }
- else
- {
- commit_output_value(gen, regs);
- }
+ commit_output_value(gen, regs, 1);
}
-
+
/* Load clobbered global registers. */
for(reg = JIT_NUM_REGS - 1; reg >= 0; reg--)
{
#endif
}
-JIT_OP_FADD, JIT_OP_DADD, JIT_OP_NFADD: stack
+JIT_OP_FADD, JIT_OP_DADD, JIT_OP_NFADD: stack, x87_arith, commutative
[freg, freg] -> {
- x86_fp_op_reg(inst, X86_FADD, 1, 1);
+ int flags;
+
+ flags = _jit_regs_select(®s);
+
+ if((flags & _JIT_REGS_NO_POP) == 0)
+ {
+ x86_fp_op_reg(inst, X86_FADD,
+ fp_stack_index(gen, $1 + JIT_REG_STACK_START), 1);
+ }
+ else if((flags & _JIT_REGS_FLIP_ARGS) != 0)
+ {
+ x86_fp_op_reg(inst, X86_FADD,
+ fp_stack_index(gen, $1 + JIT_REG_STACK_START), 0);
+ }
+ else
+ {
+ x86_fp_op(inst, X86_FADD,
+ fp_stack_index(gen, $2 + JIT_REG_STACK_START));
+ }
}
-JIT_OP_FSUB, JIT_OP_DSUB, JIT_OP_NFSUB: stack
+JIT_OP_FSUB, JIT_OP_DSUB, JIT_OP_NFSUB: stack, x87_arith_reversible
[freg, freg] -> {
- x86_fp_op_reg(inst, X86_FSUB, 1, 1);
+ int flags;
+
+ flags = _jit_regs_select(®s);
+
+ if((flags & _JIT_REGS_NO_POP) == 0)
+ {
+ if((flags & _JIT_REGS_REVERSE) == 0)
+ {
+ x86_fp_op_reg(inst, X86_FSUB,
+ fp_stack_index(gen, $1 + JIT_REG_STACK_START), 1);
+ }
+ else
+ {
+ x86_fp_op_reg(inst, X86_FSUBR,
+ fp_stack_index(gen, $2 + JIT_REG_STACK_START), 1);
+ }
+ }
+ else if((flags & _JIT_REGS_FLIP_ARGS) != 0)
+ {
+ if((flags & _JIT_REGS_REVERSE) == 0)
+ {
+ x86_fp_op_reg(inst, X86_FSUB,
+ fp_stack_index(gen, $1 + JIT_REG_STACK_START), 0);
+ }
+ else
+ {
+ x86_fp_op(inst, X86_FSUBR,
+ fp_stack_index(gen, $1 + JIT_REG_STACK_START));
+ }
+ }
+ else
+ {
+ if((flags & _JIT_REGS_REVERSE) == 0)
+ {
+ x86_fp_op(inst, X86_FSUB,
+ fp_stack_index(gen, $2 + JIT_REG_STACK_START));
+ }
+ else
+ {
+ x86_fp_op_reg(inst, X86_FSUBR,
+ fp_stack_index(gen, $2 + JIT_REG_STACK_START), 0);
+ }
+ }
}
-JIT_OP_FMUL, JIT_OP_DMUL, JIT_OP_NFMUL: stack
+JIT_OP_FMUL, JIT_OP_DMUL, JIT_OP_NFMUL: stack, x87_arith, commutative
[freg, freg] -> {
- x86_fp_op_reg(inst, X86_FMUL, 1, 1);
+ int flags;
+
+ flags = _jit_regs_select(®s);
+
+ if((flags & _JIT_REGS_NO_POP) == 0)
+ {
+ x86_fp_op_reg(inst, X86_FMUL, fp_stack_index(gen, $1 + JIT_REG_STACK_START), 1);
+ }
+ else if((flags & _JIT_REGS_FLIP_ARGS) != 0)
+ {
+ x86_fp_op_reg(inst, X86_FMUL, fp_stack_index(gen, $1 + JIT_REG_STACK_START), 0);
+ }
+ else
+ {
+ x86_fp_op(inst, X86_FMUL, fp_stack_index(gen, $2 + JIT_REG_STACK_START));
+ }
}
-JIT_OP_FDIV, JIT_OP_DDIV, JIT_OP_NFDIV: stack
+JIT_OP_FDIV, JIT_OP_DDIV, JIT_OP_NFDIV: stack, x87_arith_reversible
[freg, freg] -> {
- x86_fp_op_reg(inst, X86_FDIV, 1, 1);
+ int flags;
+
+ flags = _jit_regs_select(®s);
+
+ if((flags & _JIT_REGS_NO_POP) == 0)
+ {
+ if((flags & _JIT_REGS_REVERSE) == 0)
+ {
+ x86_fp_op_reg(inst, X86_FDIV,
+ fp_stack_index(gen, $1 + JIT_REG_STACK_START), 1);
+ }
+ else
+ {
+ x86_fp_op_reg(inst, X86_FDIVR,
+ fp_stack_index(gen, $2 + JIT_REG_STACK_START), 1);
+ }
+ }
+ else if((flags & _JIT_REGS_FLIP_ARGS) != 0)
+ {
+ if((flags & _JIT_REGS_REVERSE) == 0)
+ {
+ x86_fp_op_reg(inst, X86_FDIV,
+ fp_stack_index(gen, $1 + JIT_REG_STACK_START), 0);
+ }
+ else
+ {
+ x86_fp_op(inst, X86_FDIVR,
+ fp_stack_index(gen, $1 + JIT_REG_STACK_START));
+ }
+ }
+ else
+ {
+ if((flags & _JIT_REGS_REVERSE) == 0)
+ {
+ x86_fp_op(inst, X86_FDIV,
+ fp_stack_index(gen, $2 + JIT_REG_STACK_START));
+ }
+ else
+ {
+ x86_fp_op_reg(inst, X86_FDIVR,
+ fp_stack_index(gen, $2 + JIT_REG_STACK_START), 0);
+ }
+ }
}
JIT_OP_FREM, JIT_OP_DREM, JIT_OP_NFREM: stack
[freg, freg, scratch reg("eax")] -> {
unsigned char *label;
- x86_fxch(inst, 1);
label = inst;
x86_fprem(inst);
x86_fnstsw(inst);
*/
JIT_OP_FATAN, JIT_OP_DATAN, JIT_OP_NFATAN: stack
- [freg, clobber(freg)] -> {
+ [freg, scratch freg] -> {
x86_fld1(inst);
x86_fpatan(inst);
x86_fldz(inst);
}
JIT_OP_FCOS, JIT_OP_DCOS, JIT_OP_NFCOS: stack
- [freg, clobber(freg)] -> {
+ [freg, scratch freg] -> {
x86_fcos(inst);
x86_fldz(inst);
x86_fp_op_reg(inst, X86_FADD, 1, 1);
}
JIT_OP_FSIN, JIT_OP_DSIN, JIT_OP_NFSIN: stack
- [freg, clobber(freg)] -> {
+ [freg, scratch freg] -> {
x86_fsin(inst);
x86_fldz(inst);
x86_fp_op_reg(inst, X86_FADD, 1, 1);
x86_mov_membase_reg(inst, $1, $3 + 4, %2, 4);
}
-JIT_OP_STORE_RELATIVE_FLOAT32: ternary
+JIT_OP_STORE_RELATIVE_FLOAT32: ternary, stack
[reg, imm, imm] -> {
x86_mov_membase_imm(inst, $1, $3, ((int *)($2))[0], 4);
}
x86_fst_membase(inst, $1, $3, 0, 1);
}
-JIT_OP_STORE_RELATIVE_FLOAT64: ternary
+JIT_OP_STORE_RELATIVE_FLOAT64: ternary, stack
[reg, imm, imm] -> {
x86_mov_membase_imm(inst, $1, $3, ((int *)($2))[0], 4);
x86_mov_membase_imm(inst, $1, $3 + 4, ((int *)($2))[1], 4);
x86_fst_membase(inst, $1, $3, 1, 1);
}
-JIT_OP_STORE_RELATIVE_NFLOAT: ternary
+JIT_OP_STORE_RELATIVE_NFLOAT: ternary, stack
[reg, imm, imm] -> {
x86_mov_membase_imm(inst, $1, $3, ((int *)($2))[0], 4);
x86_mov_membase_imm(inst, $1, $3 + 4, ((int *)($2))[1], 4);
x86_mov_memindex_reg(inst, $1, 4, $2, 3, %3, 4);
}
-JIT_OP_STORE_ELEMENT_FLOAT32: ternary
+JIT_OP_STORE_ELEMENT_FLOAT32: ternary, stack
[reg, reg, freg] -> {
x86_fst_memindex(inst, $1, 0, $2, 2, 0, 1);
}
-JIT_OP_STORE_ELEMENT_FLOAT64: ternary
+JIT_OP_STORE_ELEMENT_FLOAT64: ternary, stack
[reg, reg, freg] -> {
x86_fst_memindex(inst, $1, 0, $2, 3, 1, 1);
}
-JIT_OP_STORE_ELEMENT_NFLOAT: ternary
+JIT_OP_STORE_ELEMENT_NFLOAT: ternary, stack
[reg, +reg, freg, if("sizeof(jit_nfloat) != sizeof(jit_float64)")] -> {
/* lea reg2, [reg2 + reg2 * 2] */
x86_lea_memindex(inst, $2, $2, 0, $2, 1);