mirror of https://github.com/ademakov/libjit
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1401 lines
33 KiB
1401 lines
33 KiB
/*
|
|
* 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);
|
|
}
|
|
}
|
|
|