From: Rhys Weatherley Date: Tue, 1 Jun 2004 09:55:54 +0000 (+0000) Subject: More instruction selection rules for ARM. X-Git-Tag: r.0.0.4~61 X-Git-Url: https://git.unchartedbackwaters.co.uk/w/?a=commitdiff_plain;h=f9aae1aee641ade129fdfb369531223da4387d58;p=francis%2Flibjit.git More instruction selection rules for ARM. --- diff --git a/ChangeLog b/ChangeLog index 5259272..d6167fd 100644 --- a/ChangeLog +++ b/ChangeLog @@ -4,6 +4,9 @@ * jit/jit-cache.c, jit/jit-elf-read.c, tools/gen-apply.c: fix some gcc 3.x compile warnings. + * jit/jit-rules-arm.c, jit/jit-rules-arm.sel: more instruction + selection rules for ARM. + 2004-05-31 Rhys Weatherley * jit/jit-rules-x86.sel: optimize multiplications for x86. diff --git a/jit/jit-rules-arm.c b/jit/jit-rules-arm.c index c613b73..2e7e1cd 100644 --- a/jit/jit-rules-arm.c +++ b/jit/jit-rules-arm.c @@ -26,6 +26,7 @@ #include "jit-gen-arm.h" #include "jit-reg-alloc.h" +#include /* * Determine if we actually have floating-point registers. @@ -546,6 +547,9 @@ void _jit_gen_epilog(jit_gencode_t gen, jit_function_t func) { 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)) @@ -565,6 +569,24 @@ void _jit_gen_epilog(jit_gencode_t gen, jit_function_t func) } } + /* 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); @@ -687,6 +709,73 @@ static arm_inst_ptr output_branch 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) { @@ -695,6 +784,13 @@ void _jit_gen_insn(jit_gencode_t gen, jit_function_t func, #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; } } diff --git a/jit/jit-rules-arm.sel b/jit/jit-rules-arm.sel index 7cd98ee..0fab535 100644 --- a/jit/jit-rules-arm.sel +++ b/jit/jit-rules-arm.sel @@ -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(); + } +