|
|
@ -69,8 +69,66 @@ JIT_OP_ISUB: binary |
|
|
|
|
|
|
|
JIT_OP_IMUL: binary |
|
|
|
[reg, immu8] -> { |
|
|
|
arm_mov_reg_imm8(inst, ARM_WORK, $2); |
|
|
|
arm_mul_reg_reg(inst, $1, $1, ARM_WORK); |
|
|
|
/* Handle special cases of immediate multiplies */ |
|
|
|
switch($2) |
|
|
|
{ |
|
|
|
case 0: |
|
|
|
{ |
|
|
|
arm_mov_reg_imm(inst, $1, 0); |
|
|
|
} |
|
|
|
break; |
|
|
|
|
|
|
|
case 1: break; |
|
|
|
|
|
|
|
case 2: |
|
|
|
{ |
|
|
|
arm_shift_reg_imm8(inst, ARM_SHL, $1, $1, 1); |
|
|
|
} |
|
|
|
break; |
|
|
|
|
|
|
|
case 4: |
|
|
|
{ |
|
|
|
arm_shift_reg_imm8(inst, ARM_SHL, $1, $1, 2); |
|
|
|
} |
|
|
|
break; |
|
|
|
|
|
|
|
case 8: |
|
|
|
{ |
|
|
|
arm_shift_reg_imm8(inst, ARM_SHL, $1, $1, 3); |
|
|
|
} |
|
|
|
break; |
|
|
|
|
|
|
|
case 16: |
|
|
|
{ |
|
|
|
arm_shift_reg_imm8(inst, ARM_SHL, $1, $1, 4); |
|
|
|
} |
|
|
|
break; |
|
|
|
|
|
|
|
case 32: |
|
|
|
{ |
|
|
|
arm_shift_reg_imm8(inst, ARM_SHL, $1, $1, 5); |
|
|
|
} |
|
|
|
break; |
|
|
|
|
|
|
|
case 64: |
|
|
|
{ |
|
|
|
arm_shift_reg_imm8(inst, ARM_SHL, $1, $1, 6); |
|
|
|
} |
|
|
|
break; |
|
|
|
|
|
|
|
case 128: |
|
|
|
{ |
|
|
|
arm_shift_reg_imm8(inst, ARM_SHL, $1, $1, 7); |
|
|
|
} |
|
|
|
break; |
|
|
|
|
|
|
|
default: |
|
|
|
{ |
|
|
|
arm_mov_reg_imm8(inst, ARM_WORK, $2); |
|
|
|
arm_mul_reg_reg(inst, $1, $1, ARM_WORK); |
|
|
|
} |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
[reg, reg] -> { |
|
|
|
if($1 != $2) |
|
|
@ -426,3 +484,157 @@ JIT_OP_IGE_UN: binary |
|
|
|
arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 0, ARM_CC_LT_UN); |
|
|
|
} |
|
|
|
|
|
|
|
/* |
|
|
|
* Pointer check opcodes. |
|
|
|
*/ |
|
|
|
|
|
|
|
JIT_OP_CHECK_NULL: unary_note |
|
|
|
[reg] -> { |
|
|
|
arm_test_reg_imm8(inst, ARM_CMP, $1, 0); |
|
|
|
inst = throw_builtin(inst, func, ARM_CC_EQ, JIT_RESULT_NULL_REFERENCE); |
|
|
|
} |
|
|
|
|
|
|
|
/* |
|
|
|
* Function calls. |
|
|
|
*/ |
|
|
|
|
|
|
|
JIT_OP_CALL: |
|
|
|
[] -> { |
|
|
|
jit_function_t func = (jit_function_t)(insn->dest); |
|
|
|
arm_call(inst, func->closure_entry); |
|
|
|
} |
|
|
|
|
|
|
|
JIT_OP_CALL_TAIL: |
|
|
|
[] -> { |
|
|
|
jit_function_t func = (jit_function_t)(insn->dest); |
|
|
|
arm_jump(inst, func->closure_entry); |
|
|
|
} |
|
|
|
|
|
|
|
JIT_OP_CALL_INDIRECT: |
|
|
|
[] -> { |
|
|
|
arm_mov_reg_reg((inst), ARM_LINK, ARM_PC); |
|
|
|
arm_mov_reg_reg((inst), ARM_PC, ARM_WORK); |
|
|
|
} |
|
|
|
|
|
|
|
JIT_OP_CALL_VTABLE_PTR: |
|
|
|
[] -> { |
|
|
|
arm_mov_reg_reg((inst), ARM_LINK, ARM_PC); |
|
|
|
arm_mov_reg_reg((inst), ARM_PC, ARM_WORK); |
|
|
|
} |
|
|
|
|
|
|
|
JIT_OP_CALL_EXTERNAL: |
|
|
|
[] -> { |
|
|
|
arm_call(inst, (void *)(insn->dest)); |
|
|
|
} |
|
|
|
|
|
|
|
JIT_OP_RETURN: |
|
|
|
[] -> { |
|
|
|
inst = jump_to_epilog(gen, inst, block); |
|
|
|
} |
|
|
|
|
|
|
|
JIT_OP_RETURN_INT: unary_note |
|
|
|
[reg] -> { |
|
|
|
int cpu_reg = $1; |
|
|
|
if(cpu_reg != ARM_R0) |
|
|
|
{ |
|
|
|
arm_mov_reg_reg(inst, ARM_R0, cpu_reg); |
|
|
|
} |
|
|
|
inst = jump_to_epilog(gen, inst, block); |
|
|
|
} |
|
|
|
|
|
|
|
JIT_OP_RETURN_LONG: spill_before |
|
|
|
[] -> { |
|
|
|
if(jit_value_is_constant(insn->value1)) |
|
|
|
{ |
|
|
|
arm_mov_reg_imm(inst, ARM_R0, |
|
|
|
((jit_int *)(insn->value1->address))[0]); |
|
|
|
arm_mov_reg_imm(inst, ARM_R1, |
|
|
|
((jit_int *)(insn->value1->address))[1]); |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
jit_nint offset; |
|
|
|
_jit_gen_fix_value(insn->value1); |
|
|
|
offset = insn->value1->frame_offset; |
|
|
|
arm_load_membase(inst, ARM_R0, ARM_FP, offset); |
|
|
|
arm_load_membase(inst, ARM_R1, ARM_FP, offset + 4); |
|
|
|
} |
|
|
|
inst = jump_to_epilog(gen, inst, block); |
|
|
|
} |
|
|
|
|
|
|
|
JIT_OP_RETURN_FLOAT32: manual |
|
|
|
[] -> { |
|
|
|
/* TODO */ |
|
|
|
TODO(); |
|
|
|
} |
|
|
|
|
|
|
|
JIT_OP_RETURN_FLOAT64: manual |
|
|
|
[] -> { |
|
|
|
/* TODO */ |
|
|
|
TODO(); |
|
|
|
} |
|
|
|
|
|
|
|
JIT_OP_RETURN_NFLOAT: manual |
|
|
|
[] -> { |
|
|
|
/* TODO */ |
|
|
|
TODO(); |
|
|
|
} |
|
|
|
|
|
|
|
JIT_OP_RETURN_SMALL_STRUCT: spill_before |
|
|
|
[] -> { |
|
|
|
/* TODO: load the structure value into EAX:EDX */ |
|
|
|
TODO(); |
|
|
|
inst = jump_to_epilog(gen, inst, block); |
|
|
|
} |
|
|
|
|
|
|
|
JIT_OP_SETUP_FOR_NESTED: spill_before |
|
|
|
[] -> { |
|
|
|
jit_nint nest_reg = jit_value_get_nint_constant(insn->value1); |
|
|
|
if(nest_reg == -1) |
|
|
|
{ |
|
|
|
arm_push_reg(inst, ARM_FP); |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
arm_mov_reg_reg(inst, _jit_reg_info[nest_reg].cpu_reg, ARM_FP); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
JIT_OP_SETUP_FOR_SIBLING: spill_before |
|
|
|
[] -> { |
|
|
|
jit_nint level = jit_value_get_nint_constant(insn->value1); |
|
|
|
jit_nint nest_reg = jit_value_get_nint_constant(insn->value2); |
|
|
|
int cpu_reg; |
|
|
|
if(nest_reg == -1) |
|
|
|
{ |
|
|
|
cpu_reg = ARM_R0; |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
cpu_reg = _jit_reg_info[nest_reg].cpu_reg; |
|
|
|
} |
|
|
|
arm_load_membase(inst, cpu_reg, ARM_FP, JIT_APPLY_PARENT_FRAME_OFFSET); |
|
|
|
while(level > 0) |
|
|
|
{ |
|
|
|
gen->posn.ptr = (unsigned char *)inst; |
|
|
|
if(!jit_cache_check_for_n(&(gen->posn), 16)) |
|
|
|
{ |
|
|
|
jit_cache_mark_full(&(gen->posn)); |
|
|
|
return; |
|
|
|
} |
|
|
|
arm_load_membase(inst, cpu_reg, cpu_reg, |
|
|
|
JIT_APPLY_PARENT_FRAME_OFFSET); |
|
|
|
--level; |
|
|
|
} |
|
|
|
if(nest_reg == -1) |
|
|
|
{ |
|
|
|
arm_push_reg(inst, cpu_reg); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
JIT_OP_IMPORT: |
|
|
|
[] -> { |
|
|
|
/* TODO */ |
|
|
|
TODO(); |
|
|
|
} |
|
|
|
|
|
|
|