|
|
|
/*
|
|
|
|
* jit-rules-x86.sel - Instruction selector for x86.
|
|
|
|
*
|
|
|
|
* 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
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Conversion opcodes.
|
|
|
|
*/
|
|
|
|
|
|
|
|
JIT_OP_TRUNC_SBYTE: unary
|
|
|
|
[reg] -> {
|
|
|
|
inst = widen_byte(inst, $1, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
JIT_OP_TRUNC_UBYTE: unary
|
|
|
|
[reg] -> {
|
|
|
|
inst = widen_byte(inst, $1, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
JIT_OP_TRUNC_SHORT: unary
|
|
|
|
[reg] -> {
|
|
|
|
x86_widen_reg(inst, $1, $1, 1, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
JIT_OP_TRUNC_USHORT: unary
|
|
|
|
[reg] -> {
|
|
|
|
x86_widen_reg(inst, $1, $1, 0, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Arithmetic opcodes.
|
|
|
|
*/
|
|
|
|
|
|
|
|
JIT_OP_IADD: binary
|
|
|
|
[reg, imm] -> {
|
|
|
|
x86_alu_reg_imm(inst, X86_ADD, $1, $2);
|
|
|
|
}
|
|
|
|
[reg, local] -> {
|
|
|
|
x86_alu_reg_membase(inst, X86_ADD, $1, X86_EBP, $2);
|
|
|
|
}
|
|
|
|
[reg, reg] -> {
|
|
|
|
x86_alu_reg_reg(inst, X86_ADD, $1, $2);
|
|
|
|
}
|
|
|
|
|
|
|
|
JIT_OP_ISUB: binary
|
|
|
|
[reg, imm] -> {
|
|
|
|
x86_alu_reg_imm(inst, X86_SUB, $1, $2);
|
|
|
|
}
|
|
|
|
[reg, local] -> {
|
|
|
|
x86_alu_reg_membase(inst, X86_SUB, $1, X86_EBP, $2);
|
|
|
|
}
|
|
|
|
[reg, reg] -> {
|
|
|
|
x86_alu_reg_reg(inst, X86_SUB, $1, $2);
|
|
|
|
}
|
|
|
|
|
|
|
|
JIT_OP_IMUL: binary, spill_before
|
|
|
|
[reg, reg] -> {
|
|
|
|
x86_mul_reg(inst, $2, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
JIT_OP_INEG: unary
|
|
|
|
[reg] -> {
|
|
|
|
x86_neg_reg(inst, $1);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Bitwise opcodes.
|
|
|
|
*/
|
|
|
|
|
|
|
|
JIT_OP_IAND: binary
|
|
|
|
[reg, imm] -> {
|
|
|
|
x86_alu_reg_imm(inst, X86_AND, $1, $2);
|
|
|
|
}
|
|
|
|
[reg, local] -> {
|
|
|
|
x86_alu_reg_membase(inst, X86_AND, $1, X86_EBP, $2);
|
|
|
|
}
|
|
|
|
[reg, reg] -> {
|
|
|
|
x86_alu_reg_reg(inst, X86_AND, $1, $2);
|
|
|
|
}
|
|
|
|
|
|
|
|
JIT_OP_IOR: binary
|
|
|
|
[reg, imm] -> {
|
|
|
|
x86_alu_reg_imm(inst, X86_OR, $1, $2);
|
|
|
|
}
|
|
|
|
[reg, local] -> {
|
|
|
|
x86_alu_reg_membase(inst, X86_OR, $1, X86_EBP, $2);
|
|
|
|
}
|
|
|
|
[reg, reg] -> {
|
|
|
|
x86_alu_reg_reg(inst, X86_OR, $1, $2);
|
|
|
|
}
|
|
|
|
|
|
|
|
JIT_OP_IXOR: binary
|
|
|
|
[reg, imm] -> {
|
|
|
|
x86_alu_reg_imm(inst, X86_XOR, $1, $2);
|
|
|
|
}
|
|
|
|
[reg, local] -> {
|
|
|
|
x86_alu_reg_membase(inst, X86_XOR, $1, X86_EBP, $2);
|
|
|
|
}
|
|
|
|
[reg, reg] -> {
|
|
|
|
x86_alu_reg_reg(inst, X86_XOR, $1, $2);
|
|
|
|
}
|
|
|
|
|
|
|
|
JIT_OP_INOT: unary
|
|
|
|
[reg] -> {
|
|
|
|
x86_not_reg(inst, $1);
|
|
|
|
}
|
|
|
|
|
|
|
|
JIT_OP_ISHL: binary
|
|
|
|
[reg, imm] -> {
|
|
|
|
x86_shift_reg_imm(inst, X86_SHL, $1, ($2 & 0x1F));
|
|
|
|
}
|
|
|
|
[reg, reg] -> {
|
|
|
|
inst = shift_reg(inst, X86_SHL, $1, $2);
|
|
|
|
}
|
|
|
|
|
|
|
|
JIT_OP_ISHR: binary
|
|
|
|
[reg, imm] -> {
|
|
|
|
x86_shift_reg_imm(inst, X86_SAR, $1, ($2 & 0x1F));
|
|
|
|
}
|
|
|
|
[reg, reg] -> {
|
|
|
|
inst = shift_reg(inst, X86_SAR, $1, $2);
|
|
|
|
}
|
|
|
|
|
|
|
|
JIT_OP_ISHR_UN: binary
|
|
|
|
[reg, imm] -> {
|
|
|
|
x86_shift_reg_imm(inst, X86_SHR, $1, ($2 & 0x1F));
|
|
|
|
}
|
|
|
|
[reg, reg] -> {
|
|
|
|
inst = shift_reg(inst, X86_SHR, $1, $2);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Branch opcodes.
|
|
|
|
*/
|
|
|
|
|
|
|
|
JIT_OP_BR: spill_before
|
|
|
|
[] -> {
|
|
|
|
inst = output_branch(func, inst, 0xEB /* jmp */, insn);
|
|
|
|
}
|
|
|
|
|
|
|
|
JIT_OP_BR_IFALSE: unary_branch
|
|
|
|
[reg] -> {
|
|
|
|
x86_alu_reg_reg(inst, X86_OR, $1, $1);
|
|
|
|
inst = output_branch(func, inst, 0x74 /* eq */, insn);
|
|
|
|
}
|
|
|
|
|
|
|
|
JIT_OP_BR_ITRUE: unary_branch
|
|
|
|
[reg] -> {
|
|
|
|
x86_alu_reg_reg(inst, X86_OR, $1, $1);
|
|
|
|
inst = output_branch(func, inst, 0x75 /* ne */, insn);
|
|
|
|
}
|
|
|
|
|
|
|
|
JIT_OP_BR_IEQ: binary_branch
|
|
|
|
[reg, immzero] -> {
|
|
|
|
x86_alu_reg_reg(inst, X86_OR, $1, $1);
|
|
|
|
inst = output_branch(func, inst, 0x74 /* eq */, insn);
|
|
|
|
}
|
|
|
|
[reg, imm] -> {
|
|
|
|
x86_alu_reg_imm(inst, X86_CMP, $1, $2);
|
|
|
|
inst = output_branch(func, inst, 0x74 /* eq */, insn);
|
|
|
|
}
|
|
|
|
[reg, local] -> {
|
|
|
|
x86_alu_reg_membase(inst, X86_CMP, $1, X86_EBP, $2);
|
|
|
|
inst = output_branch(func, inst, 0x74 /* eq */, insn);
|
|
|
|
}
|
|
|
|
[reg, reg] -> {
|
|
|
|
x86_alu_reg_reg(inst, X86_CMP, $1, $2);
|
|
|
|
inst = output_branch(func, inst, 0x74 /* eq */, insn);
|
|
|
|
}
|
|
|
|
|
|
|
|
JIT_OP_BR_INE: binary_branch
|
|
|
|
[reg, immzero] -> {
|
|
|
|
x86_alu_reg_reg(inst, X86_OR, $1, $1);
|
|
|
|
inst = output_branch(func, inst, 0x75 /* ne */, insn);
|
|
|
|
}
|
|
|
|
[reg, imm] -> {
|
|
|
|
x86_alu_reg_imm(inst, X86_CMP, $1, $2);
|
|
|
|
inst = output_branch(func, inst, 0x75 /* ne */, insn);
|
|
|
|
}
|
|
|
|
[reg, local] -> {
|
|
|
|
x86_alu_reg_membase(inst, X86_CMP, $1, X86_EBP, $2);
|
|
|
|
inst = output_branch(func, inst, 0x75 /* ne */, insn);
|
|
|
|
}
|
|
|
|
[reg, reg] -> {
|
|
|
|
x86_alu_reg_reg(inst, X86_CMP, $1, $2);
|
|
|
|
inst = output_branch(func, inst, 0x75 /* ne */, insn);
|
|
|
|
}
|
|
|
|
|
|
|
|
JIT_OP_BR_ILT: binary_branch
|
|
|
|
[reg, imm] -> {
|
|
|
|
x86_alu_reg_imm(inst, X86_CMP, $1, $2);
|
|
|
|
inst = output_branch(func, inst, 0x7C /* lt */, insn);
|
|
|
|
}
|
|
|
|
[reg, local] -> {
|
|
|
|
x86_alu_reg_membase(inst, X86_CMP, $1, X86_EBP, $2);
|
|
|
|
inst = output_branch(func, inst, 0x7C /* lt */, insn);
|
|
|
|
}
|
|
|
|
[reg, reg] -> {
|
|
|
|
x86_alu_reg_reg(inst, X86_CMP, $1, $2);
|
|
|
|
inst = output_branch(func, inst, 0x7C /* lt */, insn);
|
|
|
|
}
|
|
|
|
|
|
|
|
JIT_OP_BR_ILT_UN: binary_branch
|
|
|
|
[reg, imm] -> {
|
|
|
|
x86_alu_reg_imm(inst, X86_CMP, $1, $2);
|
|
|
|
inst = output_branch(func, inst, 0x72 /* lt_un */, insn);
|
|
|
|
}
|
|
|
|
[reg, local] -> {
|
|
|
|
x86_alu_reg_membase(inst, X86_CMP, $1, X86_EBP, $2);
|
|
|
|
inst = output_branch(func, inst, 0x72 /* lt_un */, insn);
|
|
|
|
}
|
|
|
|
[reg, reg] -> {
|
|
|
|
x86_alu_reg_reg(inst, X86_CMP, $1, $2);
|
|
|
|
inst = output_branch(func, inst, 0x72 /* lt_un */, insn);
|
|
|
|
}
|
|
|
|
|
|
|
|
JIT_OP_BR_ILE: binary_branch
|
|
|
|
[reg, imm] -> {
|
|
|
|
x86_alu_reg_imm(inst, X86_CMP, $1, $2);
|
|
|
|
inst = output_branch(func, inst, 0x7E /* le */, insn);
|
|
|
|
}
|
|
|
|
[reg, local] -> {
|
|
|
|
x86_alu_reg_membase(inst, X86_CMP, $1, X86_EBP, $2);
|
|
|
|
inst = output_branch(func, inst, 0x7E /* le */, insn);
|
|
|
|
}
|
|
|
|
[reg, reg] -> {
|
|
|
|
x86_alu_reg_reg(inst, X86_CMP, $1, $2);
|
|
|
|
inst = output_branch(func, inst, 0x7E /* le */, insn);
|
|
|
|
}
|
|
|
|
|
|
|
|
JIT_OP_BR_ILE_UN: binary_branch
|
|
|
|
[reg, imm] -> {
|
|
|
|
x86_alu_reg_imm(inst, X86_CMP, $1, $2);
|
|
|
|
inst = output_branch(func, inst, 0x76 /* le_un */, insn);
|
|
|
|
}
|
|
|
|
[reg, local] -> {
|
|
|
|
x86_alu_reg_membase(inst, X86_CMP, $1, X86_EBP, $2);
|
|
|
|
inst = output_branch(func, inst, 0x76 /* le_un */, insn);
|
|
|
|
}
|
|
|
|
[reg, reg] -> {
|
|
|
|
x86_alu_reg_reg(inst, X86_CMP, $1, $2);
|
|
|
|
inst = output_branch(func, inst, 0x76 /* le_un */, insn);
|
|
|
|
}
|
|
|
|
|
|
|
|
JIT_OP_BR_IGT: binary_branch
|
|
|
|
[reg, imm] -> {
|
|
|
|
x86_alu_reg_imm(inst, X86_CMP, $1, $2);
|
|
|
|
inst = output_branch(func, inst, 0x7F /* gt */, insn);
|
|
|
|
}
|
|
|
|
[reg, local] -> {
|
|
|
|
x86_alu_reg_membase(inst, X86_CMP, $1, X86_EBP, $2);
|
|
|
|
inst = output_branch(func, inst, 0x7F /* gt */, insn);
|
|
|
|
}
|
|
|
|
[reg, reg] -> {
|
|
|
|
x86_alu_reg_reg(inst, X86_CMP, $1, $2);
|
|
|
|
inst = output_branch(func, inst, 0x7F /* gt */, insn);
|
|
|
|
}
|
|
|
|
|
|
|
|
JIT_OP_BR_IGT_UN: binary_branch
|
|
|
|
[reg, imm] -> {
|
|
|
|
x86_alu_reg_imm(inst, X86_CMP, $1, $2);
|
|
|
|
inst = output_branch(func, inst, 0x77 /* gt_un */, insn);
|
|
|
|
}
|
|
|
|
[reg, local] -> {
|
|
|
|
x86_alu_reg_membase(inst, X86_CMP, $1, X86_EBP, $2);
|
|
|
|
inst = output_branch(func, inst, 0x77 /* gt_un */, insn);
|
|
|
|
}
|
|
|
|
[reg, reg] -> {
|
|
|
|
x86_alu_reg_reg(inst, X86_CMP, $1, $2);
|
|
|
|
inst = output_branch(func, inst, 0x77 /* gt_un */, insn);
|
|
|
|
}
|
|
|
|
|
|
|
|
JIT_OP_BR_IGE: binary_branch
|
|
|
|
[reg, imm] -> {
|
|
|
|
x86_alu_reg_imm(inst, X86_CMP, $1, $2);
|
|
|
|
inst = output_branch(func, inst, 0x7D /* ge */, insn);
|
|
|
|
}
|
|
|
|
[reg, local] -> {
|
|
|
|
x86_alu_reg_membase(inst, X86_CMP, $1, X86_EBP, $2);
|
|
|
|
inst = output_branch(func, inst, 0x7D /* ge */, insn);
|
|
|
|
}
|
|
|
|
[reg, reg] -> {
|
|
|
|
x86_alu_reg_reg(inst, X86_CMP, $1, $2);
|
|
|
|
inst = output_branch(func, inst, 0x7D /* ge */, insn);
|
|
|
|
}
|
|
|
|
|
|
|
|
JIT_OP_BR_IGE_UN: binary_branch
|
|
|
|
[reg, imm] -> {
|
|
|
|
x86_alu_reg_imm(inst, X86_CMP, $1, $2);
|
|
|
|
inst = output_branch(func, inst, 0x73 /* ge_un */, insn);
|
|
|
|
}
|
|
|
|
[reg, local] -> {
|
|
|
|
x86_alu_reg_membase(inst, X86_CMP, $1, X86_EBP, $2);
|
|
|
|
inst = output_branch(func, inst, 0x73 /* ge_un */, insn);
|
|
|
|
}
|
|
|
|
[reg, reg] -> {
|
|
|
|
x86_alu_reg_reg(inst, X86_CMP, $1, $2);
|
|
|
|
inst = output_branch(func, inst, 0x73 /* ge_un */, insn);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Comparison opcodes.
|
|
|
|
*/
|
|
|
|
|
|
|
|
JIT_OP_IEQ: binary
|
|
|
|
[reg, immzero] -> {
|
|
|
|
x86_alu_reg_reg(inst, X86_OR, $1, $1);
|
|
|
|
inst = setcc_reg(inst, $1, X86_CC_EQ, 0);
|
|
|
|
}
|
|
|
|
[reg, imm] -> {
|
|
|
|
x86_alu_reg_imm(inst, X86_CMP, $1, $2);
|
|
|
|
inst = setcc_reg(inst, $1, X86_CC_EQ, 0);
|
|
|
|
}
|
|
|
|
[reg, local] -> {
|
|
|
|
x86_alu_reg_membase(inst, X86_CMP, $1, X86_EBP, $2);
|
|
|
|
inst = setcc_reg(inst, $1, X86_CC_EQ, 0);
|
|
|
|
}
|
|
|
|
[reg, reg] -> {
|
|
|
|
x86_alu_reg_reg(inst, X86_CMP, $1, $2);
|
|
|
|
inst = setcc_reg(inst, $1, X86_CC_EQ, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
JIT_OP_INE: binary
|
|
|
|
[reg, immzero] -> {
|
|
|
|
x86_alu_reg_reg(inst, X86_OR, $1, $1);
|
|
|
|
inst = setcc_reg(inst, $1, X86_CC_NE, 0);
|
|
|
|
}
|
|
|
|
[reg, imm] -> {
|
|
|
|
x86_alu_reg_imm(inst, X86_CMP, $1, $2);
|
|
|
|
inst = setcc_reg(inst, $1, X86_CC_NE, 0);
|
|
|
|
}
|
|
|
|
[reg, local] -> {
|
|
|
|
x86_alu_reg_membase(inst, X86_CMP, $1, X86_EBP, $2);
|
|
|
|
inst = setcc_reg(inst, $1, X86_CC_NE, 0);
|
|
|
|
}
|
|
|
|
[reg, reg] -> {
|
|
|
|
x86_alu_reg_reg(inst, X86_CMP, $1, $2);
|
|
|
|
inst = setcc_reg(inst, $1, X86_CC_NE, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
JIT_OP_ILT: binary
|
|
|
|
[reg, imm] -> {
|
|
|
|
x86_alu_reg_imm(inst, X86_CMP, $1, $2);
|
|
|
|
inst = setcc_reg(inst, $1, X86_CC_LT, 1);
|
|
|
|
}
|
|
|
|
[reg, local] -> {
|
|
|
|
x86_alu_reg_membase(inst, X86_CMP, $1, X86_EBP, $2);
|
|
|
|
inst = setcc_reg(inst, $1, X86_CC_LT, 1);
|
|
|
|
}
|
|
|
|
[reg, reg] -> {
|
|
|
|
x86_alu_reg_reg(inst, X86_CMP, $1, $2);
|
|
|
|
inst = setcc_reg(inst, $1, X86_CC_LT, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
JIT_OP_ILT_UN: binary
|
|
|
|
[reg, imm] -> {
|
|
|
|
x86_alu_reg_imm(inst, X86_CMP, $1, $2);
|
|
|
|
inst = setcc_reg(inst, $1, X86_CC_LT, 0);
|
|
|
|
}
|
|
|
|
[reg, local] -> {
|
|
|
|
x86_alu_reg_membase(inst, X86_CMP, $1, X86_EBP, $2);
|
|
|
|
inst = setcc_reg(inst, $1, X86_CC_LT, 0);
|
|
|
|
}
|
|
|
|
[reg, reg] -> {
|
|
|
|
x86_alu_reg_reg(inst, X86_CMP, $1, $2);
|
|
|
|
inst = setcc_reg(inst, $1, X86_CC_LT, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
JIT_OP_ILE: binary
|
|
|
|
[reg, imm] -> {
|
|
|
|
x86_alu_reg_imm(inst, X86_CMP, $1, $2);
|
|
|
|
inst = setcc_reg(inst, $1, X86_CC_LE, 1);
|
|
|
|
}
|
|
|
|
[reg, local] -> {
|
|
|
|
x86_alu_reg_membase(inst, X86_CMP, $1, X86_EBP, $2);
|
|
|
|
inst = setcc_reg(inst, $1, X86_CC_LE, 1);
|
|
|
|
}
|
|
|
|
[reg, reg] -> {
|
|
|
|
x86_alu_reg_reg(inst, X86_CMP, $1, $2);
|
|
|
|
inst = setcc_reg(inst, $1, X86_CC_LE, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
JIT_OP_ILE_UN: binary
|
|
|
|
[reg, imm] -> {
|
|
|
|
x86_alu_reg_imm(inst, X86_CMP, $1, $2);
|
|
|
|
inst = setcc_reg(inst, $1, X86_CC_LE, 0);
|
|
|
|
}
|
|
|
|
[reg, local] -> {
|
|
|
|
x86_alu_reg_membase(inst, X86_CMP, $1, X86_EBP, $2);
|
|
|
|
inst = setcc_reg(inst, $1, X86_CC_LE, 0);
|
|
|
|
}
|
|
|
|
[reg, reg] -> {
|
|
|
|
x86_alu_reg_reg(inst, X86_CMP, $1, $2);
|
|
|
|
inst = setcc_reg(inst, $1, X86_CC_LE, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
JIT_OP_IGT: binary
|
|
|
|
[reg, imm] -> {
|
|
|
|
x86_alu_reg_imm(inst, X86_CMP, $1, $2);
|
|
|
|
inst = setcc_reg(inst, $1, X86_CC_GT, 1);
|
|
|
|
}
|
|
|
|
[reg, local] -> {
|
|
|
|
x86_alu_reg_membase(inst, X86_CMP, $1, X86_EBP, $2);
|
|
|
|
inst = setcc_reg(inst, $1, X86_CC_GT, 1);
|
|
|
|
}
|
|
|
|
[reg, reg] -> {
|
|
|
|
x86_alu_reg_reg(inst, X86_CMP, $1, $2);
|
|
|
|
inst = setcc_reg(inst, $1, X86_CC_GT, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
JIT_OP_IGT_UN: binary
|
|
|
|
[reg, imm] -> {
|
|
|
|
x86_alu_reg_imm(inst, X86_CMP, $1, $2);
|
|
|
|
inst = setcc_reg(inst, $1, X86_CC_GT, 0);
|
|
|
|
}
|
|
|
|
[reg, local] -> {
|
|
|
|
x86_alu_reg_membase(inst, X86_CMP, $1, X86_EBP, $2);
|
|
|
|
inst = setcc_reg(inst, $1, X86_CC_GT, 0);
|
|
|
|
}
|
|
|
|
[reg, reg] -> {
|
|
|
|
x86_alu_reg_reg(inst, X86_CMP, $1, $2);
|
|
|
|
inst = setcc_reg(inst, $1, X86_CC_GT, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
JIT_OP_IGE: binary
|
|
|
|
[reg, imm] -> {
|
|
|
|
x86_alu_reg_imm(inst, X86_CMP, $1, $2);
|
|
|
|
inst = setcc_reg(inst, $1, X86_CC_GE, 1);
|
|
|
|
}
|
|
|
|
[reg, local] -> {
|
|
|
|
x86_alu_reg_membase(inst, X86_CMP, $1, X86_EBP, $2);
|
|
|
|
inst = setcc_reg(inst, $1, X86_CC_GE, 1);
|
|
|
|
}
|
|
|
|
[reg, reg] -> {
|
|
|
|
x86_alu_reg_reg(inst, X86_CMP, $1, $2);
|
|
|
|
inst = setcc_reg(inst, $1, X86_CC_GE, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
JIT_OP_IGE_UN: binary
|
|
|
|
[reg, imm] -> {
|
|
|
|
x86_alu_reg_imm(inst, X86_CMP, $1, $2);
|
|
|
|
inst = setcc_reg(inst, $1, X86_CC_GE, 0);
|
|
|
|
}
|
|
|
|
[reg, local] -> {
|
|
|
|
x86_alu_reg_membase(inst, X86_CMP, $1, X86_EBP, $2);
|
|
|
|
inst = setcc_reg(inst, $1, X86_CC_GE, 0);
|
|
|
|
}
|
|
|
|
[reg, reg] -> {
|
|
|
|
x86_alu_reg_reg(inst, X86_CMP, $1, $2);
|
|
|
|
inst = setcc_reg(inst, $1, X86_CC_GE, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Pointer check opcodes.
|
|
|
|
*/
|
|
|
|
|
|
|
|
JIT_OP_CHECK_NULL: unary_branch
|
|
|
|
[reg] -> {
|
|
|
|
/* TODO: won't work in a function with a "try" block */
|
|
|
|
unsigned char *patch;
|
|
|
|
x86_alu_reg_reg(inst, X86_OR, $1, $1);
|
|
|
|
patch = inst;
|
|
|
|
x86_branch8(inst, X86_CC_NE, 0, 0);
|
|
|
|
x86_push_imm(inst, JIT_RESULT_NULL_REFERENCE);
|
|
|
|
x86_call_code(inst, (void *)jit_exception_builtin);
|
|
|
|
x86_patch(patch, inst);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Function calls.
|
|
|
|
*/
|
|
|
|
|
|
|
|
JIT_OP_CALL:
|
|
|
|
[] -> {
|
|
|
|
jit_function_t func = (jit_function_t)(insn->dest);
|
|
|
|
x86_call_code(inst, func->closure_entry);
|
|
|
|
}
|
|
|
|
|
|
|
|
JIT_OP_CALL_TAIL:
|
|
|
|
[] -> {
|
|
|
|
jit_function_t func = (jit_function_t)(insn->dest);
|
|
|
|
x86_jump_code(inst, func->closure_entry);
|
|
|
|
}
|
|
|
|
|
|
|
|
JIT_OP_CALL_INDIRECT:
|
|
|
|
[] -> {
|
|
|
|
x86_call_reg(inst, X86_EAX);
|
|
|
|
}
|
|
|
|
|
|
|
|
JIT_OP_CALL_VTABLE_PTR:
|
|
|
|
[] -> {
|
|
|
|
x86_call_reg(inst, X86_EAX);
|
|
|
|
}
|
|
|
|
|
|
|
|
JIT_OP_CALL_EXTERNAL:
|
|
|
|
[] -> {
|
|
|
|
x86_call_code(inst, (void *)(insn->dest));
|
|
|
|
}
|
|
|
|
|
|
|
|
JIT_OP_RETURN:
|
|
|
|
[] -> {
|
|
|
|
inst = jump_to_epilog(gen, inst, block);
|
|
|
|
}
|
|
|
|
|
|
|
|
JIT_OP_RETURN_INT: unary_branch
|
|
|
|
[reg] -> {
|
|
|
|
int cpu_reg = $1;
|
|
|
|
if(cpu_reg != X86_EAX)
|
|
|
|
{
|
|
|
|
x86_mov_reg_reg(inst, X86_EAX, cpu_reg, 4);
|
|
|
|
}
|
|
|
|
inst = jump_to_epilog(gen, inst, block);
|
|
|
|
}
|
|
|
|
|
|
|
|
JIT_OP_RETURN_LONG: spill_before
|
|
|
|
[] -> {
|
|
|
|
/* TODO: load the return value into EAX:EDX */
|
|
|
|
inst = jump_to_epilog(gen, inst, block);
|
|
|
|
}
|
|
|
|
|
|
|
|
JIT_OP_RETURN_FLOAT32: unary_branch, stack /*, only*/
|
|
|
|
[freg] -> {
|
|
|
|
inst = jump_to_epilog(gen, inst, block);
|
|
|
|
}
|
|
|
|
|
|
|
|
JIT_OP_RETURN_FLOAT64: unary_branch, stack /*, only*/
|
|
|
|
[freg] -> {
|
|
|
|
inst = jump_to_epilog(gen, inst, block);
|
|
|
|
}
|
|
|
|
|
|
|
|
JIT_OP_RETURN_NFLOAT: unary_branch, stack /*, only*/
|
|
|
|
[freg] -> {
|
|
|
|
inst = jump_to_epilog(gen, inst, block);
|
|
|
|
}
|
|
|
|
|
|
|
|
JIT_OP_RETURN_SMALL_STRUCT: spill_before
|
|
|
|
[] -> {
|
|
|
|
/* TODO: load the structure value into EAX:EDX */
|
|
|
|
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)
|
|
|
|
{
|
|
|
|
x86_push_reg(inst, X86_EBP);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
x86_mov_reg_reg(inst, _jit_reg_info[nest_reg].cpu_reg,
|
|
|
|
X86_EBP, sizeof(void *));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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 = X86_EAX;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
cpu_reg = _jit_reg_info[nest_reg].cpu_reg;
|
|
|
|
}
|
|
|
|
x86_mov_reg_membase(inst, cpu_reg, X86_EBP, 0, sizeof(void *));
|
|
|
|
while(level > 0)
|
|
|
|
{
|
|
|
|
gen->posn.ptr = inst;
|
|
|
|
if(!jit_cache_check_for_n(&(gen->posn), 16))
|
|
|
|
{
|
|
|
|
jit_cache_mark_full(&(gen->posn));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
x86_mov_reg_membase(inst, cpu_reg, cpu_reg, 0, sizeof(void *));
|
|
|
|
--level;
|
|
|
|
}
|
|
|
|
if(nest_reg == -1)
|
|
|
|
{
|
|
|
|
x86_push_reg(inst, cpu_reg);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
JIT_OP_IMPORT:
|
|
|
|
[] -> {
|
|
|
|
/* TODO */
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Stack pushes and pops.
|
|
|
|
*/
|
|
|
|
|
|
|
|
JIT_OP_PUSH_INT: unary_branch
|
|
|
|
[imm] -> {
|
|
|
|
x86_push_imm(inst, $1);
|
|
|
|
}
|
|
|
|
[local] -> {
|
|
|
|
x86_push_membase(inst, X86_EBP, $1);
|
|
|
|
}
|
|
|
|
[reg] -> {
|
|
|
|
x86_push_reg(inst, $1);
|
|
|
|
}
|
|
|
|
|
|
|
|
JIT_OP_PUSH_LONG:
|
|
|
|
[] -> {
|
|
|
|
/* TODO */
|
|
|
|
}
|
|
|
|
|
|
|
|
JIT_OP_PUSH_FLOAT32:
|
|
|
|
[] -> {
|
|
|
|
/* TODO */
|
|
|
|
}
|
|
|
|
|
|
|
|
JIT_OP_PUSH_FLOAT64:
|
|
|
|
[] -> {
|
|
|
|
/* TODO */
|
|
|
|
}
|
|
|
|
|
|
|
|
JIT_OP_PUSH_NFLOAT:
|
|
|
|
[] -> {
|
|
|
|
/* TODO */
|
|
|
|
}
|
|
|
|
|
|
|
|
JIT_OP_PUSH_STRUCT:
|
|
|
|
[] -> {
|
|
|
|
/* TODO */
|
|
|
|
}
|
|
|
|
|
|
|
|
JIT_OP_POP_STACK:
|
|
|
|
[] -> {
|
|
|
|
x86_alu_reg_imm(inst, X86_ADD, X86_ESP, insn->value1->address);
|
|
|
|
}
|
|
|
|
|
|
|
|
JIT_OP_FLUSH_SMALL_STRUCT:
|
|
|
|
[] -> {
|
|
|
|
/* TODO */
|
|
|
|
}
|