#include "jit-gen-arm.h"
#include "jit-reg-alloc.h"
+#include <stdio.h>
/*
* Determine if we actually have floating-point registers.
{
int reg, regset;
arm_inst_ptr inst;
+ void **fixup;
+ void **next;
+ jit_nint offset;
/* Bail out if there is insufficient space for the epilog */
if(!jit_cache_check_for_n(&(gen->posn), 4))
}
}
+ /* Apply fixups for blocks that jump to the epilog */
+ fixup = (void **)(gen->epilog_fixup);
+ while(fixup != 0)
+ {
+ offset = (((jit_nint)(fixup[0])) & 0x00FFFFFF) << 2;
+ if(!offset)
+ {
+ next = 0;
+ }
+ else
+ {
+ next = (void **)(((unsigned char *)fixup) - offset);
+ }
+ arm_patch(fixup, gen->posn.ptr);
+ fixup = next;
+ }
+ gen->epilog_fixup = 0;
+
/* Pop the local stack frame and return */
inst = (arm_inst_ptr)(gen->posn.ptr);
arm_pop_frame(inst, regset);
return inst;
}
+/*
+ * Throw a builtin exception.
+ */
+static arm_inst_ptr throw_builtin
+ (arm_inst_ptr inst, jit_function_t func, int cond, int type)
+{
+#if 0
+ /* TODO: port to ARM */
+ /* We need to update "catch_pc" if we have a "try" block */
+ if(func->builder->setjmp_value != 0)
+ {
+ _jit_gen_fix_value(func->builder->setjmp_value);
+ x86_call_imm(inst, 0);
+ x86_pop_membase(inst, X86_EBP,
+ func->builder->setjmp_value->frame_offset +
+ jit_jmp_catch_pc_offset);
+ }
+
+ /* Push the exception type onto the stack */
+ x86_push_imm(inst, type);
+
+ /* Call the "jit_exception_builtin" function, which will never return */
+ x86_call_code(inst, jit_exception_builtin);
+#endif
+ return inst;
+}
+
+/*
+ * Jump to the current function's epilog.
+ */
+static arm_inst_ptr jump_to_epilog
+ (jit_gencode_t gen, arm_inst_ptr inst, jit_block_t block)
+{
+ int offset;
+
+ /* If the epilog is the next thing that we will output,
+ then fall through to the epilog directly */
+ block = block->next;
+ while(block != 0 && block->first_insn > block->last_insn)
+ {
+ block = block->next;
+ }
+ if(!block)
+ {
+ return inst;
+ }
+
+ /* Output a placeholder for the jump and add it to the fixup list */
+ if(gen->epilog_fixup)
+ {
+ offset = (int)(((unsigned char *)inst) -
+ ((unsigned char *)(gen->epilog_fixup)));
+ }
+ else
+ {
+ offset = 0;
+ }
+ arm_branch_imm(inst, ARM_CC_AL, offset);
+ gen->epilog_fixup = (void *)(inst - 1);
+ return inst;
+}
+
+#define TODO() \
+ do { \
+ fprintf(stderr, "TODO at %s, %d\n", __FILE__, (int)__LINE__); \
+ } while (0)
+
void _jit_gen_insn(jit_gencode_t gen, jit_function_t func,
jit_block_t block, jit_insn_t insn)
{
#define JIT_INCLUDE_RULES
#include "jit-rules-arm.slc"
#undef JIT_INCLUDE_RULES
+
+ default:
+ {
+ fprintf(stderr, "TODO(%x) at %s, %d\n",
+ (int)(insn->opcode), __FILE__, (int)__LINE__);
+ }
+ break;
}
}
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)
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();
+ }
+