/* * jit-rules-arm.sel - Instruction selector for ARM. * * Copyright (C) 2004 Southern Storm Software, Pty Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ %inst_type arm_inst_buf /* * Conversion opcodes. */ JIT_OP_TRUNC_SBYTE: unary [reg] -> { arm_shift_reg_imm8(inst, ARM_SHL, $1, $1, 24); arm_shift_reg_imm8(inst, ARM_SAR, $1, $1, 24); } JIT_OP_TRUNC_UBYTE: unary [reg] -> { arm_alu_reg_imm8(inst, ARM_AND, $1, $1, 0xFF); } JIT_OP_TRUNC_SHORT: unary [reg] -> { arm_shift_reg_imm8(inst, ARM_SHL, $1, $1, 16); arm_shift_reg_imm8(inst, ARM_SAR, $1, $1, 16); } JIT_OP_TRUNC_USHORT: unary [reg] -> { arm_shift_reg_imm8(inst, ARM_SHL, $1, $1, 16); arm_shift_reg_imm8(inst, ARM_SHR, $1, $1, 16); } /* * Arithmetic opcodes. */ JIT_OP_IADD: binary [reg, immu8] -> { arm_alu_reg_imm8(inst, ARM_ADD, $1, $1, $2); } [reg, reg] -> { arm_alu_reg_reg(inst, ARM_ADD, $1, $1, $2); } JIT_OP_ISUB: binary [reg, immu8] -> { arm_alu_reg_imm8(inst, ARM_SUB, $1, $1, $2); } [reg, reg] -> { arm_alu_reg_reg(inst, ARM_SUB, $1, $1, $2); } JIT_OP_IMUL: binary [reg, immu8] -> { /* Handle special cases of immediate multiplies */ switch($2) { case 0: { arm_mov_reg_imm8(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_mul_reg_reg(inst, $1, $1, $2); } else { /* Cannot use the same register for both arguments */ arm_mov_reg_reg(inst, ARM_WORK, $2); arm_mul_reg_reg(inst, $1, $1, ARM_WORK); } } JIT_OP_INEG: unary [reg] -> { /* -x is the same as (0 - x) */ arm_alu_reg_imm8(inst, ARM_RSB, $1, $1, 0); } JIT_OP_LADD: binary [lreg, lreg] -> { arm_alu_cc_reg_reg(inst, ARM_ADD, $1, $1, $2); arm_alu_reg_reg(inst, ARM_ADC, %1, %1, %2); } JIT_OP_LSUB: binary [lreg, lreg] -> { arm_alu_cc_reg_reg(inst, ARM_SUB, $1, $1, $2); arm_alu_reg_reg(inst, ARM_SBC, %1, %1, %2); } JIT_OP_LNEG: unary [lreg] -> { arm_alu_reg(inst, ARM_MVN, $1, $1); arm_alu_reg(inst, ARM_MVN, %1, %1); arm_alu_cc_reg_imm8(inst, ARM_ADD, $1, $1, 1); arm_alu_reg_imm8(inst, ARM_ADC, %1, %1, 0); } JIT_OP_FADD (JIT_ARM_HAS_FLOAT_REGS): binary [freg, freg] -> { arm_alu_freg_freg_32(inst, ARM_ADF, $1, $1, $2); } JIT_OP_FSUB (JIT_ARM_HAS_FLOAT_REGS): binary [freg, freg] -> { arm_alu_freg_freg_32(inst, ARM_SUF, $1, $1, $2); } JIT_OP_FMUL (JIT_ARM_HAS_FLOAT_REGS): binary [freg, freg] -> { arm_alu_freg_freg_32(inst, ARM_MUF, $1, $1, $2); } JIT_OP_FDIV (JIT_ARM_HAS_FLOAT_REGS): binary [freg, freg] -> { arm_alu_freg_freg_32(inst, ARM_DVF, $1, $1, $2); } JIT_OP_FNEG (JIT_ARM_HAS_FLOAT_REGS): unary [freg] -> { arm_alu_freg_32(inst, ARM_MNF, $1, $1); } JIT_OP_DADD, JIT_OP_NFADD (JIT_ARM_HAS_FLOAT_REGS): binary [freg, freg] -> { arm_alu_freg_freg(inst, ARM_ADF, $1, $1, $2); } JIT_OP_DSUB, JIT_OP_NFSUB (JIT_ARM_HAS_FLOAT_REGS): binary [freg, freg] -> { arm_alu_freg_freg(inst, ARM_SUF, $1, $1, $2); } JIT_OP_DMUL, JIT_OP_NFMUL (JIT_ARM_HAS_FLOAT_REGS): binary [freg, freg] -> { arm_alu_freg_freg(inst, ARM_MUF, $1, $1, $2); } JIT_OP_DDIV, JIT_OP_NFDIV (JIT_ARM_HAS_FLOAT_REGS): binary [freg, freg] -> { arm_alu_freg_freg(inst, ARM_DVF, $1, $1, $2); } JIT_OP_DNEG, JIT_OP_NFNEG (JIT_ARM_HAS_FLOAT_REGS): unary [freg] -> { arm_alu_freg(inst, ARM_MNF, $1, $1); } /* * Bitwise opcodes. */ JIT_OP_IAND: binary [reg, immu8] -> { arm_alu_reg_imm8(inst, ARM_AND, $1, $1, $2); } [reg, reg] -> { arm_alu_reg_reg(inst, ARM_AND, $1, $1, $2); } JIT_OP_IOR: binary [reg, immu8] -> { arm_alu_reg_imm8(inst, ARM_ORR, $1, $1, $2); } [reg, reg] -> { arm_alu_reg_reg(inst, ARM_ORR, $1, $1, $2); } JIT_OP_IXOR: binary [reg, immu8] -> { arm_alu_reg_imm8(inst, ARM_EOR, $1, $1, $2); } [reg, reg] -> { arm_alu_reg_reg(inst, ARM_EOR, $1, $1, $2); } JIT_OP_INOT: unary [reg] -> { /* MVN == "move not" */ arm_alu_reg(inst, ARM_MVN, $1, $1); } JIT_OP_ISHL: binary [reg, imm] -> { arm_shift_reg_imm8(inst, ARM_SHL, $1, $1, ($2 & 0x1F)); } [reg, reg] -> { arm_alu_reg_imm8(inst, ARM_AND, ARM_WORK, $2, 0x1F); arm_shift_reg_reg(inst, ARM_SHL, $1, $1, ARM_WORK); } JIT_OP_ISHR: binary [reg, imm] -> { arm_shift_reg_imm8(inst, ARM_SAR, $1, $1, ($2 & 0x1F)); } [reg, reg] -> { arm_alu_reg_imm8(inst, ARM_AND, ARM_WORK, $2, 0x1F); arm_shift_reg_reg(inst, ARM_SAR, $1, $1, ARM_WORK); } JIT_OP_ISHR_UN: binary [reg, imm] -> { arm_shift_reg_imm8(inst, ARM_SHR, $1, $1, ($2 & 0x1F)); } [reg, reg] -> { arm_alu_reg_imm8(inst, ARM_AND, ARM_WORK, $2, 0x1F); arm_shift_reg_reg(inst, ARM_SHR, $1, $1, ARM_WORK); } JIT_OP_LAND: binary [lreg, lreg] -> { arm_alu_reg_reg(inst, ARM_AND, $1, $1, $2); arm_alu_reg_reg(inst, ARM_AND, %1, %1, %2); } JIT_OP_LOR: binary [lreg, lreg] -> { arm_alu_reg_reg(inst, ARM_ORR, $1, $1, $2); arm_alu_reg_reg(inst, ARM_ORR, %1, %1, %2); } JIT_OP_LXOR: binary [lreg, lreg] -> { arm_alu_reg_reg(inst, ARM_EOR, $1, $1, $2); arm_alu_reg_reg(inst, ARM_EOR, %1, %1, %2); } JIT_OP_LNOT: unary [lreg] -> { arm_alu_reg(inst, ARM_MVN, $1, $1); arm_alu_reg(inst, ARM_MVN, %1, %1); } /* * Branch opcodes. */ JIT_OP_BR: spill_before [] -> { /* ARM_CC_AL == "always branch" */ output_branch(func, &inst, ARM_CC_AL, insn); /* Flush the constant pool now, to minimize the probability that it is accidentally flushed in the middle of a loop body */ jit_gen_save_inst_ptr(gen, inst); flush_constants(gen, 1); jit_gen_load_inst_ptr(gen, inst); } JIT_OP_BR_IFALSE: unary_branch [reg] -> { arm_test_reg_imm8(inst, ARM_CMP, $1, 0); output_branch(func, &inst, ARM_CC_EQ, insn); } JIT_OP_BR_ITRUE: unary_branch [reg] -> { arm_test_reg_imm8(inst, ARM_CMP, $1, 0); output_branch(func, &inst, ARM_CC_NE, insn); } JIT_OP_BR_IEQ: binary_branch [reg, immu8] -> { arm_test_reg_imm8(inst, ARM_CMP, $1, $2); output_branch(func, &inst, ARM_CC_EQ, insn); } [reg, reg] -> { arm_test_reg_reg(inst, ARM_CMP, $1, $2); output_branch(func, &inst, ARM_CC_EQ, insn); } JIT_OP_BR_INE: binary_branch [reg, immu8] -> { arm_test_reg_imm8(inst, ARM_CMP, $1, $2); output_branch(func, &inst, ARM_CC_NE, insn); } [reg, reg] -> { arm_test_reg_reg(inst, ARM_CMP, $1, $2); output_branch(func, &inst, ARM_CC_NE, insn); } JIT_OP_BR_ILT: binary_branch [reg, immu8] -> { arm_test_reg_imm8(inst, ARM_CMP, $1, $2); output_branch(func, &inst, ARM_CC_LT, insn); } [reg, reg] -> { arm_test_reg_reg(inst, ARM_CMP, $1, $2); output_branch(func, &inst, ARM_CC_LT, insn); } JIT_OP_BR_ILT_UN: binary_branch [reg, immu8] -> { arm_test_reg_imm8(inst, ARM_CMP, $1, $2); output_branch(func, &inst, ARM_CC_LT_UN, insn); } [reg, reg] -> { arm_test_reg_reg(inst, ARM_CMP, $1, $2); output_branch(func, &inst, ARM_CC_LT_UN, insn); } JIT_OP_BR_ILE: binary_branch [reg, immu8] -> { arm_test_reg_imm8(inst, ARM_CMP, $1, $2); output_branch(func, &inst, ARM_CC_LE, insn); } [reg, reg] -> { arm_test_reg_reg(inst, ARM_CMP, $1, $2); output_branch(func, &inst, ARM_CC_LE, insn); } JIT_OP_BR_ILE_UN: binary_branch [reg, immu8] -> { arm_test_reg_imm8(inst, ARM_CMP, $1, $2); output_branch(func, &inst, ARM_CC_LE_UN, insn); } [reg, reg] -> { arm_test_reg_reg(inst, ARM_CMP, $1, $2); output_branch(func, &inst, ARM_CC_LE_UN, insn); } JIT_OP_BR_IGT: binary_branch [reg, immu8] -> { arm_test_reg_imm8(inst, ARM_CMP, $1, $2); output_branch(func, &inst, ARM_CC_GT, insn); } [reg, reg] -> { arm_test_reg_reg(inst, ARM_CMP, $1, $2); output_branch(func, &inst, ARM_CC_GT, insn); } JIT_OP_BR_IGT_UN: binary_branch [reg, immu8] -> { arm_test_reg_imm8(inst, ARM_CMP, $1, $2); output_branch(func, &inst, ARM_CC_GT_UN, insn); } [reg, reg] -> { arm_test_reg_reg(inst, ARM_CMP, $1, $2); output_branch(func, &inst, ARM_CC_GT_UN, insn); } JIT_OP_BR_IGE: binary_branch [reg, immu8] -> { arm_test_reg_imm8(inst, ARM_CMP, $1, $2); output_branch(func, &inst, ARM_CC_GE, insn); } [reg, reg] -> { arm_test_reg_reg(inst, ARM_CMP, $1, $2); output_branch(func, &inst, ARM_CC_GE, insn); } JIT_OP_BR_IGE_UN: binary_branch [reg, immu8] -> { arm_test_reg_imm8(inst, ARM_CMP, $1, $2); output_branch(func, &inst, ARM_CC_GE_UN, insn); } [reg, reg] -> { arm_test_reg_reg(inst, ARM_CMP, $1, $2); output_branch(func, &inst, ARM_CC_GE_UN, insn); } /* * Comparison opcodes. */ JIT_OP_ICMP: binary [reg, immu8] -> { arm_test_reg_imm8(inst, ARM_CMP, $1, $2); arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 1, ARM_CC_GT); arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 0, ARM_CC_LE); arm_alu_reg_cond(inst, ARM_MVN, $1, $1, ARM_CC_LT); } [reg, reg] -> { arm_test_reg_reg(inst, ARM_CMP, $1, $2); arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 1, ARM_CC_GT); arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 0, ARM_CC_LE); arm_alu_reg_cond(inst, ARM_MVN, $1, $1, ARM_CC_LT); } JIT_OP_ICMP_UN: binary [reg, immu8] -> { arm_test_reg_imm8(inst, ARM_CMP, $1, $2); arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 1, ARM_CC_GT_UN); arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 0, ARM_CC_LE_UN); arm_alu_reg_cond(inst, ARM_MVN, $1, $1, ARM_CC_LT_UN); } [reg, reg] -> { arm_test_reg_reg(inst, ARM_CMP, $1, $2); arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 1, ARM_CC_GT_UN); arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 0, ARM_CC_LE_UN); arm_alu_reg_cond(inst, ARM_MVN, $1, $1, ARM_CC_LT_UN); } JIT_OP_IEQ: binary [reg, immu8] -> { arm_test_reg_imm8(inst, ARM_CMP, $1, $2); arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 1, ARM_CC_EQ); arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 0, ARM_CC_NE); } [reg, reg] -> { arm_test_reg_reg(inst, ARM_CMP, $1, $2); arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 1, ARM_CC_EQ); arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 0, ARM_CC_NE); } JIT_OP_INE: binary [reg, immu8] -> { arm_test_reg_imm8(inst, ARM_CMP, $1, $2); arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 1, ARM_CC_NE); arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 0, ARM_CC_EQ); } [reg, reg] -> { arm_test_reg_reg(inst, ARM_CMP, $1, $2); arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 1, ARM_CC_NE); arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 0, ARM_CC_EQ); } JIT_OP_ILT: binary [reg, immu8] -> { arm_test_reg_imm8(inst, ARM_CMP, $1, $2); arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 1, ARM_CC_LT); arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 0, ARM_CC_GE); } [reg, reg] -> { arm_test_reg_reg(inst, ARM_CMP, $1, $2); arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 1, ARM_CC_LT); arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 0, ARM_CC_GE); } JIT_OP_ILT_UN: binary [reg, immu8] -> { arm_test_reg_imm8(inst, ARM_CMP, $1, $2); arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 1, ARM_CC_LT_UN); arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 0, ARM_CC_GE_UN); } [reg, reg] -> { arm_test_reg_reg(inst, ARM_CMP, $1, $2); arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 1, ARM_CC_LT_UN); arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 0, ARM_CC_GE_UN); } JIT_OP_ILE: binary [reg, immu8] -> { arm_test_reg_imm8(inst, ARM_CMP, $1, $2); arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 1, ARM_CC_LE); arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 0, ARM_CC_GT); } [reg, reg] -> { arm_test_reg_reg(inst, ARM_CMP, $1, $2); arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 1, ARM_CC_LE); arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 0, ARM_CC_GT); } JIT_OP_ILE_UN: binary [reg, immu8] -> { arm_test_reg_imm8(inst, ARM_CMP, $1, $2); arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 1, ARM_CC_LE_UN); arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 0, ARM_CC_GT_UN); } [reg, reg] -> { arm_test_reg_reg(inst, ARM_CMP, $1, $2); arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 1, ARM_CC_LE_UN); arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 0, ARM_CC_GT_UN); } JIT_OP_IGT: binary [reg, immu8] -> { arm_test_reg_imm8(inst, ARM_CMP, $1, $2); arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 1, ARM_CC_GT); arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 0, ARM_CC_LE); } [reg, reg] -> { arm_test_reg_reg(inst, ARM_CMP, $1, $2); arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 1, ARM_CC_GT); arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 0, ARM_CC_LE); } JIT_OP_IGT_UN: binary [reg, immu8] -> { arm_test_reg_imm8(inst, ARM_CMP, $1, $2); arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 1, ARM_CC_GT_UN); arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 0, ARM_CC_LE_UN); } [reg, reg] -> { arm_test_reg_reg(inst, ARM_CMP, $1, $2); arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 1, ARM_CC_GT_UN); arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 0, ARM_CC_LE_UN); } JIT_OP_IGE: binary [reg, immu8] -> { arm_test_reg_imm8(inst, ARM_CMP, $1, $2); arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 1, ARM_CC_GE); arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 0, ARM_CC_LT); } [reg, reg] -> { arm_test_reg_reg(inst, ARM_CMP, $1, $2); arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 1, ARM_CC_GE); arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 0, ARM_CC_LT); } JIT_OP_IGE_UN: binary [reg, immu8] -> { arm_test_reg_imm8(inst, ARM_CMP, $1, $2); arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 1, ARM_CC_GE_UN); arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 0, ARM_CC_LT_UN); } [reg, reg] -> { arm_test_reg_reg(inst, ARM_CMP, $1, $2); arm_alu_reg_imm8_cond(inst, ARM_MOV, $1, 0, 1, ARM_CC_GE_UN); 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); 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_pop_frame_tail(inst, 0); 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: [] -> { jump_to_epilog(gen, &inst, block); } JIT_OP_RETURN_INT: unary_branch [reg] -> { int cpu_reg = $1; if(cpu_reg != ARM_R0) { arm_mov_reg_reg(inst, ARM_R0, cpu_reg); } jump_to_epilog(gen, &inst, block); } JIT_OP_RETURN_LONG: unary_branch [imm] -> { mov_reg_imm(gen, &inst, ARM_R0, ((jit_int *)($1))[0]); mov_reg_imm(gen, &inst, ARM_R1, ((jit_int *)($1))[1]); jump_to_epilog(gen, &inst, block); } [local] -> { arm_load_membase(inst, ARM_R0, ARM_FP, $1); arm_load_membase(inst, ARM_R1, ARM_FP, $1 + 4); jump_to_epilog(gen, &inst, block); } [lreg] -> { if($1 != 0) { arm_mov_reg_reg(inst, ARM_R0, $1); arm_mov_reg_reg(inst, ARM_R1, %1); } jump_to_epilog(gen, &inst, block); } JIT_OP_RETURN_FLOAT32 (JIT_ARM_HAS_FLOAT_REGS): unary_branch [freg] -> { if($1 != 0) { arm_alu_freg_32(inst, ARM_MVF, ARM_F0, $1); } jump_to_epilog(gen, &inst, block); } JIT_OP_RETURN_FLOAT32 (!JIT_ARM_HAS_FLOAT_REGS): manual [] -> { arm_inst_buf inst; _jit_regs_spill_all(gen); _jit_gen_fix_value(insn->value1); jit_gen_load_inst_ptr(gen, inst); if(insn->value1->is_constant) { mov_reg_imm (gen, &inst, ARM_R0, ((int *)(insn->value1->address))[0]); } else { arm_load_membase(inst, ARM_R0, ARM_FP, insn->value1->frame_offset); } jump_to_epilog(gen, &inst, block); jit_gen_save_inst_ptr(gen, inst); } JIT_OP_RETURN_FLOAT64, JIT_OP_RETURN_NFLOAT (JIT_ARM_HAS_FLOAT_REGS): unary_branch [freg] -> { if($1 != 0) { arm_alu_freg(inst, ARM_MVF, ARM_F0, $1); } jump_to_epilog(gen, &inst, block); } JIT_OP_RETURN_FLOAT64, JIT_OP_RETURN_NFLOAT (!JIT_ARM_HAS_FLOAT_REGS): manual [] -> { arm_inst_buf inst; _jit_regs_spill_all(gen); _jit_gen_fix_value(insn->value1); jit_gen_load_inst_ptr(gen, inst); if(insn->value1->is_constant) { mov_reg_imm (gen, &inst, ARM_R0, ((int *)(insn->value1->address))[0]); mov_reg_imm (gen, &inst, ARM_R1, ((int *)(insn->value1->address))[1]); } else { arm_load_membase(inst, ARM_R0, ARM_FP, insn->value1->frame_offset); arm_load_membase(inst, ARM_R1, ARM_FP, insn->value1->frame_offset + 4); } jump_to_epilog(gen, &inst, block); jit_gen_save_inst_ptr(gen, inst); } JIT_OP_RETURN_SMALL_STRUCT: unary_branch [reg] -> { int temp_reg = $1; if(temp_reg < 3) { arm_mov_reg_reg(inst, ARM_WORK, temp_reg); temp_reg = ARM_WORK; } switch(insn->value2->address) { case 1: { arm_load_membase_byte(inst, ARM_R0, temp_reg, 0); } break; case 2: { arm_load_membase_ushort(inst, ARM_R0, temp_reg, 0); } break; case 3: { arm_load_membase_ushort(inst, ARM_R0, temp_reg, 0); arm_load_membase_byte(inst, ARM_R1, temp_reg, 2); arm_shift_reg_imm8(inst, ARM_SHL, ARM_R1, ARM_R1, 16); arm_alu_reg_reg(inst, ARM_ORR, ARM_R0, ARM_R0, ARM_R1); } break; case 4: { arm_load_membase(inst, ARM_R0, temp_reg, 0); } break; case 5: { arm_load_membase(inst, ARM_R0, temp_reg, 0); arm_load_membase_byte(inst, ARM_R1, temp_reg, 4); } break; case 6: { arm_load_membase(inst, ARM_R0, temp_reg, 0); arm_load_membase_ushort(inst, ARM_R1, temp_reg, 4); } break; case 7: { arm_load_membase(inst, ARM_R0, temp_reg, 0); arm_load_membase_ushort(inst, ARM_R1, temp_reg, 4); arm_load_membase_byte(inst, ARM_R2, temp_reg, 6); arm_shift_reg_imm8(inst, ARM_SHL, ARM_R2, ARM_R2, 16); arm_alu_reg_reg(inst, ARM_ORR, ARM_R1, ARM_R1, ARM_R2); } break; case 8: { arm_load_membase(inst, ARM_R0, temp_reg, 0); arm_load_membase(inst, ARM_R1, temp_reg, 4); } break; } 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) { 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(); } /* * Data manipulation. */ JIT_OP_COPY_LOAD_SBYTE: unary [reg] -> {} JIT_OP_COPY_LOAD_UBYTE: unary [reg] -> {} JIT_OP_COPY_LOAD_SHORT: unary [reg] -> {} JIT_OP_COPY_LOAD_USHORT: unary [reg] -> {} JIT_OP_COPY_INT: unary [reg] -> {} JIT_OP_COPY_LONG: unary [lreg] -> {} JIT_OP_COPY_FLOAT32 (JIT_ARM_HAS_FLOAT_REGS): unary [freg] -> {} JIT_OP_COPY_FLOAT32 (!JIT_ARM_HAS_FLOAT_REGS): manual [] -> { arm_inst_buf inst; _jit_regs_force_out(gen, insn->value1, 0); _jit_regs_force_out(gen, insn->dest, 1); _jit_gen_fix_value(insn->value1); _jit_gen_fix_value(insn->dest); jit_gen_load_inst_ptr(gen, inst); if(insn->value1->is_constant) { mov_reg_imm (gen, &inst, ARM_WORK, ((int *)(insn->value1->address))[0]); } else { arm_load_membase(inst, ARM_WORK, ARM_FP, insn->value1->frame_offset); } arm_store_membase(inst, ARM_WORK, ARM_FP, insn->dest->frame_offset); jit_gen_save_inst_ptr(gen, inst); } JIT_OP_COPY_FLOAT64, JIT_OP_COPY_NFLOAT (JIT_ARM_HAS_FLOAT_REGS): unary [freg] -> {} JIT_OP_COPY_FLOAT64, JIT_OP_COPY_NFLOAT (!JIT_ARM_HAS_FLOAT_REGS): manual [] -> { arm_inst_buf inst; _jit_regs_force_out(gen, insn->value1, 0); _jit_regs_force_out(gen, insn->dest, 1); _jit_gen_fix_value(insn->value1); _jit_gen_fix_value(insn->dest); jit_gen_load_inst_ptr(gen, inst); if(insn->value1->is_constant) { mov_reg_imm (gen, &inst, ARM_WORK, ((int *)(insn->value1->address))[0]); arm_store_membase(inst, ARM_WORK, ARM_FP, insn->dest->frame_offset); mov_reg_imm (gen, &inst, ARM_WORK, ((int *)(insn->value1->address))[1]); arm_store_membase(inst, ARM_WORK, ARM_FP, insn->dest->frame_offset + 4); } else { arm_load_membase(inst, ARM_WORK, ARM_FP, insn->value1->frame_offset); arm_store_membase(inst, ARM_WORK, ARM_FP, insn->dest->frame_offset); arm_load_membase(inst, ARM_WORK, ARM_FP, insn->value1->frame_offset + 4); arm_store_membase(inst, ARM_WORK, ARM_FP, insn->dest->frame_offset + 4); } jit_gen_save_inst_ptr(gen, inst); } JIT_OP_COPY_STRUCT: manual [] -> { /* TODO */ TODO(); } JIT_OP_COPY_STORE_BYTE: manual [] -> { arm_inst_buf inst; int reg; _jit_regs_force_out(gen, insn->dest, 1); _jit_gen_fix_value(insn->dest); reg = _jit_regs_load_value (gen, insn->value1, 0, (insn->flags & (JIT_INSN_VALUE1_NEXT_USE | JIT_INSN_VALUE1_LIVE))); jit_gen_load_inst_ptr(gen, inst); arm_store_membase_byte(inst, _jit_reg_info[reg].cpu_reg, ARM_FP, insn->dest->frame_offset); jit_gen_save_inst_ptr(gen, inst); } JIT_OP_COPY_STORE_SHORT: manual [] -> { arm_inst_buf inst; int reg; _jit_regs_force_out(gen, insn->dest, 1); _jit_gen_fix_value(insn->dest); reg = _jit_regs_load_value (gen, insn->value1, 1, (insn->flags & (JIT_INSN_VALUE1_NEXT_USE | JIT_INSN_VALUE1_LIVE))); jit_gen_load_inst_ptr(gen, inst); arm_store_membase_short(inst, _jit_reg_info[reg].cpu_reg, ARM_FP, insn->dest->frame_offset); jit_gen_save_inst_ptr(gen, inst); _jit_regs_free_reg(gen, reg, 1); } JIT_OP_ADDRESS_OF: manual [] -> { arm_inst_buf inst; int reg, offset; _jit_regs_force_out(gen, insn->value1, 0); _jit_gen_fix_value(insn->value1); jit_gen_load_inst_ptr(gen, inst); reg = _jit_regs_dest_value(gen, insn->dest); reg = _jit_reg_info[reg].cpu_reg; offset = insn->value1->frame_offset; if(offset > 0) { arm_alu_reg_imm(inst, ARM_ADD, reg, ARM_FP, offset); } else if(offset < 0) { arm_alu_reg_imm(inst, ARM_SUB, reg, ARM_FP, -offset); } else { arm_mov_reg_reg(inst, reg, ARM_FP); } jit_gen_save_inst_ptr(gen, inst); } /* * Stack pushes and pops. */ JIT_OP_RETURN_REG: manual [] -> { /* Nothing to do here */ } JIT_OP_PUSH_INT: unary_note [reg] -> { arm_push_reg(inst, $1); } JIT_OP_PUSH_LONG: unary_note [lreg] -> { arm_push_reg(inst, %1); arm_push_reg(inst, $1); } JIT_OP_PUSH_FLOAT32 (JIT_ARM_HAS_FLOAT_REGS): unary_note [freg] -> { arm_push_reg_float32(inst, $1); } JIT_OP_PUSH_FLOAT32 (!JIT_ARM_HAS_FLOAT_REGS): manual [] -> { arm_inst_buf inst; _jit_regs_force_out(gen, insn->value1, 0); _jit_gen_fix_value(insn->value1); jit_gen_load_inst_ptr(gen, inst); if(insn->value1->is_constant) { mov_reg_imm (gen, &inst, ARM_WORK, ((int *)(insn->value1->address))[0]); } else { arm_load_membase(inst, ARM_WORK, ARM_FP, insn->value1->frame_offset); } arm_push_reg(inst, ARM_WORK); jit_gen_save_inst_ptr(gen, inst); } JIT_OP_PUSH_FLOAT64, JIT_OP_PUSH_NFLOAT (JIT_ARM_HAS_FLOAT_REGS): unary_note [freg] -> { arm_push_reg_float64(inst, $1); } JIT_OP_PUSH_FLOAT64, JIT_OP_PUSH_NFLOAT (!JIT_ARM_HAS_FLOAT_REGS): manual [] -> { arm_inst_buf inst; _jit_regs_force_out(gen, insn->value1, 0); _jit_gen_fix_value(insn->value1); jit_gen_load_inst_ptr(gen, inst); if(insn->value1->is_constant) { mov_reg_imm (gen, &inst, ARM_WORK, ((int *)(insn->value1->address))[1]); arm_push_reg(inst, ARM_WORK); mov_reg_imm (gen, &inst, ARM_WORK, ((int *)(insn->value1->address))[0]); arm_push_reg(inst, ARM_WORK); } else { arm_load_membase(inst, ARM_WORK, ARM_FP, insn->value1->frame_offset + 4); arm_push_reg(inst, ARM_WORK); arm_load_membase(inst, ARM_WORK, ARM_FP, insn->value1->frame_offset); arm_push_reg(inst, ARM_WORK); } jit_gen_save_inst_ptr(gen, inst); } JIT_OP_PUSH_STRUCT: unary_note [reg] -> { /* TODO */ TODO(); } JIT_OP_POP_STACK: [] -> { arm_alu_reg_imm(inst, ARM_ADD, ARM_SP, ARM_SP, insn->value1->address); } JIT_OP_FLUSH_SMALL_STRUCT: [] -> { jit_nuint size; jit_nint offset; _jit_gen_fix_value(insn->value1); size = jit_type_get_size(jit_value_get_type(insn->value1)); offset = insn->value1->frame_offset; switch(size) { case 1: { arm_store_membase_byte(inst, ARM_R0, ARM_FP, offset); } break; case 2: { arm_store_membase_short(inst, ARM_R0, ARM_FP, offset); } break; case 3: { arm_mov_reg_reg(inst, ARM_R1, ARM_R0); arm_store_membase_short(inst, ARM_R0, ARM_FP, offset); arm_shift_reg_imm8(inst, ARM_SHR, ARM_R0, ARM_R1, 16); arm_store_membase_byte(inst, ARM_R0, ARM_FP, offset + 2); } break; case 4: { arm_store_membase(inst, ARM_R0, ARM_FP, offset); } break; case 5: { arm_store_membase(inst, ARM_R0, ARM_FP, offset); arm_store_membase_byte(inst, ARM_R1, ARM_FP, offset + 4); } break; case 6: { arm_store_membase(inst, ARM_R0, ARM_FP, offset); arm_store_membase_short(inst, ARM_R1, ARM_FP, offset + 4); } break; case 7: { arm_store_membase(inst, ARM_R0, ARM_FP, offset); arm_mov_reg_reg(inst, ARM_R2, ARM_R1); arm_store_membase_short(inst, ARM_R1, ARM_FP, offset + 4); arm_shift_reg_imm8(inst, ARM_SHR, ARM_R1, ARM_R2, 16); arm_store_membase_byte(inst, ARM_R1, ARM_FP, offset + 6); } break; case 8: { arm_store_membase(inst, ARM_R0, ARM_FP, offset); arm_store_membase(inst, ARM_R1, ARM_FP, offset + 4); } break; } } JIT_OP_SET_PARAM_INT: unary_note [reg] -> { arm_store_membase(inst, $1, ARM_SP, insn->value2->address); } JIT_OP_SET_PARAM_LONG: unary_note [lreg] -> { arm_store_membase(inst, $1, ARM_SP, insn->value2->address); arm_store_membase(inst, %1, ARM_SP, insn->value2->address + 4); } JIT_OP_SET_PARAM_FLOAT32 (JIT_ARM_HAS_FLOAT_REGS): unary_note [freg] -> { arm_store_membase_float32(inst, $1, ARM_SP, insn->value2->address); } JIT_OP_SET_PARAM_FLOAT32 (!JIT_ARM_HAS_FLOAT_REGS): manual [] -> { arm_inst_buf inst; _jit_regs_force_out(gen, insn->value1, 0); _jit_gen_fix_value(insn->value1); jit_gen_load_inst_ptr(gen, inst); if(insn->value1->is_constant) { mov_reg_imm (gen, &inst, ARM_WORK, ((int *)(insn->value1->address))[0]); arm_store_membase (inst, ARM_WORK, ARM_SP, insn->value2->address); } else { arm_load_membase(inst, ARM_WORK, ARM_FP, insn->value1->frame_offset); arm_store_membase (inst, ARM_WORK, ARM_SP, insn->value2->address); } jit_gen_save_inst_ptr(gen, inst); } JIT_OP_SET_PARAM_FLOAT64, JIT_OP_SET_PARAM_NFLOAT (JIT_ARM_HAS_FLOAT_REGS): unary_note [freg] -> { arm_store_membase_float64(inst, $1, ARM_SP, insn->value2->address); } JIT_OP_SET_PARAM_FLOAT64, JIT_OP_SET_PARAM_NFLOAT (!JIT_ARM_HAS_FLOAT_REGS): manual [] -> { arm_inst_buf inst; _jit_regs_force_out(gen, insn->value1, 0); _jit_gen_fix_value(insn->value1); jit_gen_load_inst_ptr(gen, inst); if(insn->value1->is_constant) { mov_reg_imm (gen, &inst, ARM_WORK, ((int *)(insn->value1->address))[0]); arm_store_membase (inst, ARM_WORK, ARM_SP, insn->value2->address); mov_reg_imm (gen, &inst, ARM_WORK, ((int *)(insn->value1->address))[1]); arm_store_membase (inst, ARM_WORK, ARM_SP, insn->value2->address + 4); } else { arm_load_membase(inst, ARM_WORK, ARM_FP, insn->value1->frame_offset); arm_store_membase (inst, ARM_WORK, ARM_SP, insn->value2->address); arm_load_membase(inst, ARM_WORK, ARM_FP, insn->value1->frame_offset + 4); arm_store_membase (inst, ARM_WORK, ARM_SP, insn->value2->address + 4); } jit_gen_save_inst_ptr(gen, inst); } JIT_OP_SET_PARAM_STRUCT: unary_note [reg] -> { /* TODO */ TODO(); } /* * Pointer-relative loads and stores. */ JIT_OP_LOAD_RELATIVE_SBYTE: unary [reg] -> { arm_load_membase_sbyte(inst, $1, $1, insn->value2->address); } JIT_OP_LOAD_RELATIVE_UBYTE: unary [reg] -> { arm_load_membase_byte(inst, $1, $1, insn->value2->address); } JIT_OP_LOAD_RELATIVE_SHORT: unary [reg] -> { arm_load_membase_short(inst, $1, $1, insn->value2->address); } JIT_OP_LOAD_RELATIVE_USHORT: unary [reg] -> { arm_load_membase_ushort(inst, $1, $1, insn->value2->address); } JIT_OP_LOAD_RELATIVE_INT: unary [reg] -> { arm_load_membase(inst, $1, $1, insn->value2->address); } JIT_OP_LOAD_RELATIVE_LONG: manual [] -> { arm_inst_buf inst; int reg = _jit_regs_load_value (gen, insn->value1, 0, (insn->flags & (JIT_INSN_VALUE1_NEXT_USE | JIT_INSN_VALUE1_LIVE))); int reg2, reg3; int frame_offset; _jit_gen_fix_value(insn->dest); _jit_regs_get_reg_pair(gen, reg, -1, -1, ®2, ®3); reg = _jit_reg_info[reg].cpu_reg; reg2 = _jit_reg_info[reg2].cpu_reg; reg3 = _jit_reg_info[reg3].cpu_reg; frame_offset = insn->dest->frame_offset; jit_gen_load_inst_ptr(gen, inst); arm_load_membase(inst, reg2, reg, insn->value2->address); arm_load_membase(inst, reg3, reg, insn->value2->address + 4); arm_store_membase(inst, reg2, ARM_FP, frame_offset); arm_store_membase(inst, reg3, ARM_FP, frame_offset + 4); insn->dest->in_frame = 1; jit_gen_save_inst_ptr(gen, inst); } JIT_OP_LOAD_RELATIVE_FLOAT32: manual [] -> { /* TODO */ TODO(); } JIT_OP_LOAD_RELATIVE_FLOAT64, JIT_OP_LOAD_RELATIVE_NFLOAT: manual [] -> { /* TODO */ TODO(); } JIT_OP_LOAD_RELATIVE_STRUCT: manual [] -> { /* TODO */ TODO(); } JIT_OP_STORE_RELATIVE_BYTE: manual [] -> { arm_inst_buf inst; int reg = _jit_regs_load_value (gen, insn->dest, 0, (insn->flags & (JIT_INSN_DEST_NEXT_USE | JIT_INSN_DEST_LIVE))); int reg2 = _jit_regs_load_value (gen, insn->value1, 0, (insn->flags & (JIT_INSN_VALUE1_NEXT_USE | JIT_INSN_VALUE1_LIVE))); jit_gen_load_inst_ptr(gen, inst); reg = _jit_reg_info[reg].cpu_reg; reg2 = _jit_reg_info[reg2].cpu_reg; arm_store_membase_byte(inst, reg2, reg, insn->value2->address); jit_gen_save_inst_ptr(gen, inst); } JIT_OP_STORE_RELATIVE_SHORT: manual [] -> { arm_inst_buf inst; int reg = _jit_regs_load_value (gen, insn->dest, 0, (insn->flags & (JIT_INSN_DEST_NEXT_USE | JIT_INSN_DEST_LIVE))); int reg2 = _jit_regs_load_value (gen, insn->value1, 1, (insn->flags & (JIT_INSN_VALUE1_NEXT_USE | JIT_INSN_VALUE1_LIVE))); jit_gen_load_inst_ptr(gen, inst); reg = _jit_reg_info[reg].cpu_reg; reg2 = _jit_reg_info[reg2].cpu_reg; arm_store_membase_short(inst, reg2, reg, insn->value2->address); jit_gen_save_inst_ptr(gen, inst); _jit_regs_free_reg(gen, reg2, 1); } JIT_OP_STORE_RELATIVE_INT: manual [] -> { arm_inst_buf inst; int reg = _jit_regs_load_value (gen, insn->dest, 0, (insn->flags & (JIT_INSN_DEST_NEXT_USE | JIT_INSN_DEST_LIVE))); int reg2 = _jit_regs_load_value (gen, insn->value1, 0, (insn->flags & (JIT_INSN_VALUE1_NEXT_USE | JIT_INSN_VALUE1_LIVE))); jit_gen_load_inst_ptr(gen, inst); reg = _jit_reg_info[reg].cpu_reg; reg2 = _jit_reg_info[reg2].cpu_reg; arm_store_membase(inst, reg2, reg, insn->value2->address); jit_gen_save_inst_ptr(gen, inst); } JIT_OP_STORE_RELATIVE_LONG: manual [] -> { arm_inst_buf inst; int reg = _jit_regs_load_value (gen, insn->dest, 0, (insn->flags & (JIT_INSN_DEST_NEXT_USE | JIT_INSN_DEST_LIVE))); int reg2, reg3; int frame_offset; _jit_regs_get_reg_pair(gen, reg, -1, -1, ®2, ®3); _jit_gen_fix_value(insn->value1); jit_gen_load_inst_ptr(gen, inst); reg = _jit_reg_info[reg].cpu_reg; reg2 = _jit_reg_info[reg2].cpu_reg; reg3 = _jit_reg_info[reg3].cpu_reg; frame_offset = insn->value1->frame_offset; arm_load_membase(inst, reg2, ARM_FP, frame_offset); arm_load_membase(inst, reg3, ARM_FP, frame_offset + 4); arm_store_membase(inst, reg2, reg, insn->value2->address); arm_store_membase(inst, reg3, reg, insn->value2->address + 4); jit_gen_save_inst_ptr(gen, inst); } JIT_OP_STORE_RELATIVE_FLOAT32: manual [] -> { /* TODO */ TODO(); } JIT_OP_STORE_RELATIVE_FLOAT64, JIT_OP_STORE_RELATIVE_NFLOAT: manual [] -> { /* TODO */ TODO(); } JIT_OP_STORE_RELATIVE_STRUCT: manual [] -> { /* TODO */ TODO(); } JIT_OP_ADD_RELATIVE: unary [reg] -> { if(insn->value2->address != 0) { arm_alu_reg_imm(inst, ARM_ADD, $1, $1, insn->value2->address); } }