* might seem that there is no chance to find any dead value on the current
* instruction. However if the value is used by the current instruction both
* as the input and output then it was alive after the last instruction and
- * hence was not freed. Also the old allocator might sometimes leave a dead
- * value in the register and as of this writing the old allocator is still
- * used by some rules. And just in case if some dead value may creep through
- * the new allocator...
+ * hence was not freed. And just in case if some dead values may creep through
+ * the allocator's checks...
*/
static int
value_usage(_jit_regs_t *regs, jit_value_t value)
else if(index == 0)
{
/* this is the output value of a binary or unary op */
+
+ /* special case: a copy operation. Check if we could coalesce
+ the destination value with the source. */
+ if(regs->copy
+ && regs->descs[1].value
+ && regs->descs[1].value->in_register
+ && regs->descs[1].value->reg == reg
+ && ((regs->descs[0].value->in_register && regs->descs[0].value->reg == reg)
+ || gen->contents[reg].num_values < JIT_MAX_REG_VALUES
+ || !(regs->descs[1].used || regs->descs[1].live)))
+ {
+ return CLOBBER_NONE;
+ }
+
flags = CLOBBER_NONE;
if(is_register_alive(gen, regs, reg))
{
}
return flags;
}
+ else if(regs->copy)
+ {
+ flags = CLOBBER_NONE;
+ }
else if(regs->on_stack && !regs->no_pop)
{
/* this is a binary or unary stack op -- the input value
return 1;
}
- /* Find the registers the value is already in (if any). */
+ /* Find the register the value is already in (if any). */
if(desc->value->in_register)
{
reg = desc->value->reg;
}
else if(desc->load)
{
- if(desc->used)
- {
- if(clobber_input)
- {
- desc->kill = 1;
- }
- }
- else
+ if(!desc->used || clobber_input)
{
desc->kill = 1;
}
still_in_frame = 0;
}
- gen->contents[reg].values[0] = value;
- gen->contents[reg].num_values = 1;
+ gen->contents[reg].values[gen->contents[reg].num_values] = value;
+ ++(gen->contents[reg].num_values);
gen->contents[reg].age = gen->current_age;
gen->contents[reg].used_for_temp = 0;
gen->contents[reg].is_long_end = 0;
* Conversion opcodes.
*/
-JIT_OP_TRUNC_SBYTE: unary
- [reg("eax"|"ecx"|"edx"|"ebx")] -> {
- x86_widen_reg(inst, $1, $1, 1, 0);
+JIT_OP_TRUNC_SBYTE:
+ [=reg, reg("eax"|"ecx"|"edx"|"ebx")] -> {
+ x86_widen_reg(inst, $1, $2, 1, 0);
}
-JIT_OP_TRUNC_UBYTE: unary
- [reg("eax"|"ecx"|"edx"|"ebx")] -> {
- x86_widen_reg(inst, $1, $1, 0, 0);
+JIT_OP_TRUNC_UBYTE:
+ [=reg, reg("eax"|"ecx"|"edx"|"ebx")] -> {
+ x86_widen_reg(inst, $1, $2, 0, 0);
}
-JIT_OP_TRUNC_SHORT: unary
- [reg] -> {
- x86_widen_reg(inst, $1, $1, 1, 1);
+JIT_OP_TRUNC_SHORT:
+ [=reg, reg] -> {
+ x86_widen_reg(inst, $1, $2, 1, 1);
}
-JIT_OP_TRUNC_USHORT: unary
- [reg] -> {
- x86_widen_reg(inst, $1, $1, 0, 1);
+JIT_OP_TRUNC_USHORT:
+ [=reg, reg] -> {
+ x86_widen_reg(inst, $1, $2, 0, 1);
}
-JIT_OP_CHECK_SBYTE: unary, more_space
+JIT_OP_CHECK_SBYTE: more_space
[reg] -> {
unsigned char *patch1;
unsigned char *patch2;
x86_patch(patch2, inst);
}
-JIT_OP_CHECK_UBYTE: unary, more_space
+JIT_OP_CHECK_UBYTE: more_space
[reg] -> {
unsigned char *patch1;
x86_alu_reg_imm(inst, X86_CMP, $1, 256);
x86_patch(patch1, inst);
}
-JIT_OP_CHECK_SHORT: unary, more_space
+JIT_OP_CHECK_SHORT: more_space
[reg] -> {
unsigned char *patch1;
unsigned char *patch2;
x86_patch(patch2, inst);
}
-JIT_OP_CHECK_USHORT: unary, more_space
+JIT_OP_CHECK_USHORT: more_space
[reg] -> {
unsigned char *patch1;
x86_alu_reg_imm(inst, X86_CMP, $1, 65536);
x86_patch(patch1, inst);
}
-JIT_OP_CHECK_INT, JIT_OP_CHECK_UINT: unary, more_space
+JIT_OP_CHECK_INT, JIT_OP_CHECK_UINT: copy, more_space
[reg] -> {
unsigned char *patch1;
x86_alu_reg_imm(inst, X86_CMP, $1, 0);
inst = throw_builtin(inst, func, JIT_RESULT_OVERFLOW);
x86_patch(patch1, inst);
}
-
+
JIT_OP_LOW_WORD:
[=reg, imm] -> {
jit_uint value = ((jit_uint *)($2))[0];
x86_alu_reg_imm(inst, X86_ADD, X86_ESP, sizeof(jit_float64));
}
-JIT_OP_FLOAT32_TO_NFLOAT, JIT_OP_FLOAT64_TO_NFLOAT: unary, stack
+JIT_OP_FLOAT32_TO_NFLOAT, JIT_OP_FLOAT64_TO_NFLOAT: copy, stack
[freg] -> {
/* Nothing to do: loading the value onto the FP stack is sufficient */
}
* Data manipulation.
*/
-JIT_OP_COPY_LOAD_SBYTE: unary
+JIT_OP_COPY_LOAD_SBYTE: copy
[reg] -> {}
-JIT_OP_COPY_LOAD_UBYTE: unary
+JIT_OP_COPY_LOAD_UBYTE: copy
[reg] -> {}
-JIT_OP_COPY_LOAD_SHORT: unary
+JIT_OP_COPY_LOAD_SHORT: copy
[reg] -> {}
-JIT_OP_COPY_LOAD_USHORT: unary
+JIT_OP_COPY_LOAD_USHORT: copy
[reg] -> {}
-JIT_OP_COPY_INT: unary
+JIT_OP_COPY_INT: copy
[reg] -> {}
-JIT_OP_COPY_LONG: unary
+JIT_OP_COPY_LONG: copy
[lreg] -> {}
-JIT_OP_COPY_FLOAT32: unary, stack
+JIT_OP_COPY_FLOAT32: copy, stack
[freg] -> {}
-JIT_OP_COPY_FLOAT64: unary, stack
+JIT_OP_COPY_FLOAT64: copy, stack
[freg] -> {}
-JIT_OP_COPY_NFLOAT: unary, stack
+JIT_OP_COPY_NFLOAT: copy, stack
[freg] -> {}
JIT_OP_COPY_STRUCT: manual, spill_before