|
|
|
/*
|
|
|
|
* 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
|
|
|
|
[reg, imm] -> {
|
|
|
|
/* Handle special cases of immediate multiplies */
|
|
|
|
switch($2)
|
|
|
|
{
|
|
|
|
case 0:
|
|
|
|
{
|
|
|
|
x86_clear_reg(inst, $1);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 1: break;
|
|
|
|
|
|
|
|
case -1:
|
|
|
|
{
|
|
|
|
x86_neg_reg(inst, $1);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 2:
|
|
|
|
{
|
|
|
|
x86_shift_reg_imm(inst, X86_SHL, $1, 1);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 3:
|
|
|
|
{
|
|
|
|
/* lea reg, [reg + reg * 2] */
|
|
|
|
x86_lea_memindex(inst, $1, $1, 0, $1, 1);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 4:
|
|
|
|
{
|
|
|
|
x86_shift_reg_imm(inst, X86_SHL, $1, 2);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 5:
|
|
|
|
{
|
|
|
|
/* lea reg, [reg + reg * 4] */
|
|
|
|
x86_lea_memindex(inst, $1, $1, 0, $1, 2);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 6:
|
|
|
|
{
|
|
|
|
/* lea reg, [reg + reg * 2]; add reg, reg */
|
|
|
|
x86_lea_memindex(inst, $1, $1, 0, $1, 1);
|
|
|
|
x86_alu_reg_reg(inst, X86_ADD, $1, $1);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 8:
|
|
|
|
{
|
|
|
|
x86_shift_reg_imm(inst, X86_SHL, $1, 3);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 9:
|
|
|
|
{
|
|
|
|
/* lea reg, [reg + reg * 8] */
|
|
|
|
x86_lea_memindex(inst, $1, $1, 0, $1, 3);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 10:
|
|
|
|
{
|
|
|
|
/* lea reg, [reg + reg * 4]; add reg, reg */
|
|
|
|
x86_lea_memindex(inst, $1, $1, 0, $1, 2);
|
|
|
|
x86_alu_reg_reg(inst, X86_ADD, $1, $1);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 12:
|
|
|
|
{
|
|
|
|
/* lea reg, [reg + reg * 2]; shl reg, 2 */
|
|
|
|
x86_lea_memindex(inst, $1, $1, 0, $1, 1);
|
|
|
|
x86_shift_reg_imm(inst, X86_SHL, $1, 2);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 16:
|
|
|
|
{
|
|
|
|
x86_shift_reg_imm(inst, X86_SHL, $1, 4);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 25:
|
|
|
|
{
|
|
|
|
/* lea reg, [reg + reg * 4]; lea reg, [reg + reg * 4] */
|
|
|
|
x86_lea_memindex(inst, $1, $1, 0, $1, 2);
|
|
|
|
x86_lea_memindex(inst, $1, $1, 0, $1, 2);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 32:
|
|
|
|
{
|
|
|
|
x86_shift_reg_imm(inst, X86_SHL, $1, 5);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 64:
|
|
|
|
{
|
|
|
|
x86_shift_reg_imm(inst, X86_SHL, $1, 6);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 100:
|
|
|
|
{
|
|
|
|
/* lea reg, [reg + reg * 4]; shl reg, 2;
|
|
|
|
lea reg, [reg + reg * 4] */
|
|
|
|
x86_lea_memindex(inst, $1, $1, 0, $1, 2);
|
|
|
|
x86_shift_reg_imm(inst, X86_SHL, $1, 2);
|
|
|
|
x86_lea_memindex(inst, $1, $1, 0, $1, 2);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 128:
|
|
|
|
{
|
|
|
|
x86_shift_reg_imm(inst, X86_SHL, $1, 7);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 256:
|
|
|
|
{
|
|
|
|
x86_shift_reg_imm(inst, X86_SHL, $1, 8);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 512:
|
|
|
|
{
|
|
|
|
x86_shift_reg_imm(inst, X86_SHL, $1, 9);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 1024:
|
|
|
|
{
|
|
|
|
x86_shift_reg_imm(inst, X86_SHL, $1, 10);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 2048:
|
|
|
|
{
|
|
|
|
x86_shift_reg_imm(inst, X86_SHL, $1, 11);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 4096:
|
|
|
|
{
|
|
|
|
x86_shift_reg_imm(inst, X86_SHL, $1, 12);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 8192:
|
|
|
|
{
|
|
|
|
x86_shift_reg_imm(inst, X86_SHL, $1, 13);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 16384:
|
|
|
|
{
|
|
|
|
x86_shift_reg_imm(inst, X86_SHL, $1, 14);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 32768:
|
|
|
|
{
|
|
|
|
x86_shift_reg_imm(inst, X86_SHL, $1, 15);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 65536:
|
|
|
|
{
|
|
|
|
x86_shift_reg_imm(inst, X86_SHL, $1, 16);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x00020000:
|
|
|
|
{
|
|
|
|
x86_shift_reg_imm(inst, X86_SHL, $1, 17);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x00040000:
|
|
|
|
{
|
|
|
|
x86_shift_reg_imm(inst, X86_SHL, $1, 18);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x00080000:
|
|
|
|
{
|
|
|
|
x86_shift_reg_imm(inst, X86_SHL, $1, 19);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x00100000:
|
|
|
|
{
|
|
|
|
x86_shift_reg_imm(inst, X86_SHL, $1, 20);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x00200000:
|
|
|
|
{
|
|
|
|
x86_shift_reg_imm(inst, X86_SHL, $1, 21);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x00400000:
|
|
|
|
{
|
|
|
|
x86_shift_reg_imm(inst, X86_SHL, $1, 22);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x00800000:
|
|
|
|
{
|
|
|
|
x86_shift_reg_imm(inst, X86_SHL, $1, 23);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x01000000:
|
|
|
|
{
|
|
|
|
x86_shift_reg_imm(inst, X86_SHL, $1, 24);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x02000000:
|
|
|
|
{
|
|
|
|
x86_shift_reg_imm(inst, X86_SHL, $1, 25);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x04000000:
|
|
|
|
{
|
|
|
|
x86_shift_reg_imm(inst, X86_SHL, $1, 26);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x08000000:
|
|
|
|
{
|
|
|
|
x86_shift_reg_imm(inst, X86_SHL, $1, 27);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x10000000:
|
|
|
|
{
|
|
|
|
x86_shift_reg_imm(inst, X86_SHL, $1, 28);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x20000000:
|
|
|
|
{
|
|
|
|
x86_shift_reg_imm(inst, X86_SHL, $1, 29);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x40000000:
|
|
|
|
{
|
|
|
|
x86_shift_reg_imm(inst, X86_SHL, $1, 30);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case (jit_nint)0x80000000:
|
|
|
|
{
|
|
|
|
x86_shift_reg_imm(inst, X86_SHL, $1, 31);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
{
|
|
|
|
x86_imul_reg_reg_imm(inst, $1, $1, $2);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
[reg, local] -> {
|
|
|
|
x86_imul_reg_membase(inst, $1, X86_EBP, $2);
|
|
|
|
}
|
|
|
|
[reg, reg] -> {
|
|
|
|
x86_imul_reg_reg(inst, $1, $2);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Spill before division to ensure that the arguments end up in
|
|
|
|
EAX and ECX, and that EDX is free */
|
|
|
|
JIT_OP_IDIV: binary, spill_before, more_space
|
|
|
|
[reg, imm] -> {
|
|
|
|
switch($2)
|
|
|
|
{
|
|
|
|
case 0:
|
|
|
|
{
|
|
|
|
inst = throw_builtin(inst, func, JIT_RESULT_DIVISION_BY_ZERO);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 1: break;
|
|
|
|
|
|
|
|
case -1:
|
|
|
|
{
|
|
|
|
/* Dividing by -1 gives an exception if the argument
|
|
|
|
is minint, or simply negates for other values */
|
|
|
|
unsigned char *patch = inst;
|
|
|
|
x86_alu_reg_imm(inst, X86_CMP, $1, jit_min_int);
|
|
|
|
x86_branch8(inst, X86_CC_NE, 0, 0);
|
|
|
|
inst = throw_builtin(inst, func, JIT_RESULT_ARITHMETIC);
|
|
|
|
x86_patch(patch, inst);
|
|
|
|
x86_neg_reg(inst, $1);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 2:
|
|
|
|
{
|
|
|
|
x86_shift_reg_imm(inst, X86_SAR, $1, 1);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 4:
|
|
|
|
{
|
|
|
|
x86_shift_reg_imm(inst, X86_SAR, $1, 2);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 8:
|
|
|
|
{
|
|
|
|
x86_shift_reg_imm(inst, X86_SAR, $1, 3);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 16:
|
|
|
|
{
|
|
|
|
x86_shift_reg_imm(inst, X86_SAR, $1, 4);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 32:
|
|
|
|
{
|
|
|
|
x86_shift_reg_imm(inst, X86_SAR, $1, 5);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 64:
|
|
|
|
{
|
|
|
|
x86_shift_reg_imm(inst, X86_SAR, $1, 6);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 128:
|
|
|
|
{
|
|
|
|
x86_shift_reg_imm(inst, X86_SAR, $1, 7);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 256:
|
|
|
|
{
|
|
|
|
x86_shift_reg_imm(inst, X86_SAR, $1, 8);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 512:
|
|
|
|
{
|
|
|
|
x86_shift_reg_imm(inst, X86_SAR, $1, 9);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 1024:
|
|
|
|
{
|
|
|
|
x86_shift_reg_imm(inst, X86_SAR, $1, 10);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 2048:
|
|
|
|
{
|
|
|
|
x86_shift_reg_imm(inst, X86_SAR, $1, 11);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 4096:
|
|
|
|
{
|
|
|
|
x86_shift_reg_imm(inst, X86_SAR, $1, 12);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 8192:
|
|
|
|
{
|
|
|
|
x86_shift_reg_imm(inst, X86_SAR, $1, 13);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 16384:
|
|
|
|
{
|
|
|
|
x86_shift_reg_imm(inst, X86_SAR, $1, 14);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 32768:
|
|
|
|
{
|
|
|
|
x86_shift_reg_imm(inst, X86_SAR, $1, 15);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 65536:
|
|
|
|
{
|
|
|
|
x86_shift_reg_imm(inst, X86_SAR, $1, 16);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x00020000:
|
|
|
|
{
|
|
|
|
x86_shift_reg_imm(inst, X86_SAR, $1, 17);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x00040000:
|
|
|
|
{
|
|
|
|
x86_shift_reg_imm(inst, X86_SAR, $1, 18);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x00080000:
|
|
|
|
{
|
|
|
|
x86_shift_reg_imm(inst, X86_SAR, $1, 19);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x00100000:
|
|
|
|
{
|
|
|
|
x86_shift_reg_imm(inst, X86_SAR, $1, 20);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x00200000:
|
|
|
|
{
|
|
|
|
x86_shift_reg_imm(inst, X86_SAR, $1, 21);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x00400000:
|
|
|
|
{
|
|
|
|
x86_shift_reg_imm(inst, X86_SAR, $1, 22);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x00800000:
|
|
|
|
{
|
|
|
|
x86_shift_reg_imm(inst, X86_SAR, $1, 23);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x01000000:
|
|
|
|
{
|
|
|
|
x86_shift_reg_imm(inst, X86_SAR, $1, 24);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x02000000:
|
|
|
|
{
|
|
|
|
x86_shift_reg_imm(inst, X86_SAR, $1, 25);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x04000000:
|
|
|
|
{
|
|
|
|
x86_shift_reg_imm(inst, X86_SAR, $1, 26);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x08000000:
|
|
|
|
{
|
|
|
|
x86_shift_reg_imm(inst, X86_SAR, $1, 27);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x10000000:
|
|
|
|
{
|
|
|
|
x86_shift_reg_imm(inst, X86_SAR, $1, 28);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x20000000:
|
|
|
|
{
|
|
|
|
x86_shift_reg_imm(inst, X86_SAR, $1, 29);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x40000000:
|
|
|
|
{
|
|
|
|
x86_shift_reg_imm(inst, X86_SAR, $1, 30);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case (jit_nint)0x80000000:
|
|
|
|
{
|
|
|
|
x86_shift_reg_imm(inst, X86_SAR, $1, 31);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
{
|
|
|
|
x86_mov_reg_imm(inst, X86_ECX, $2);
|
|
|
|
x86_cdq(inst);
|
|
|
|
x86_div_reg(inst, X86_ECX, 1);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
[reg, reg] -> {
|
|
|
|
unsigned char *patch, *patch2;
|
|
|
|
x86_alu_reg_reg(inst, X86_OR, $2, $2);
|
|
|
|
patch = inst;
|
|
|
|
x86_branch8(inst, X86_CC_NE, 0, 0);
|
|
|
|
inst = throw_builtin(inst, func, JIT_RESULT_DIVISION_BY_ZERO);
|
|
|
|
x86_patch(patch, inst);
|
|
|
|
x86_alu_reg_imm(inst, X86_CMP, $2, -1);
|
|
|
|
patch = inst;
|
|
|
|
x86_branch8(inst, X86_CC_NE, 0, 0);
|
|
|
|
x86_alu_reg_imm(inst, X86_CMP, $1, jit_min_int);
|
|
|
|
patch2 = inst;
|
|
|
|
x86_branch8(inst, X86_CC_NE, 0, 0);
|
|
|
|
inst = throw_builtin(inst, func, JIT_RESULT_ARITHMETIC);
|
|
|
|
x86_patch(patch, inst);
|
|
|
|
x86_patch(patch2, inst);
|
|
|
|
x86_cdq(inst);
|
|
|
|
x86_div_reg(inst, $2, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
JIT_OP_IDIV_UN: binary, spill_before, more_space
|
|
|
|
[reg, imm] -> {
|
|
|
|
switch($2)
|
|
|
|
{
|
|
|
|
case 0:
|
|
|
|
{
|
|
|
|
inst = throw_builtin(inst, func, JIT_RESULT_DIVISION_BY_ZERO);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 1: break;
|
|
|
|
|
|
|
|
case 2:
|
|
|
|
{
|
|
|
|
x86_shift_reg_imm(inst, X86_SHR, $1, 1);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 4:
|
|
|
|
{
|
|
|
|
x86_shift_reg_imm(inst, X86_SHR, $1, 2);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 8:
|
|
|
|
{
|
|
|
|
x86_shift_reg_imm(inst, X86_SHR, $1, 3);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 16:
|
|
|
|
{
|
|
|
|
x86_shift_reg_imm(inst, X86_SHR, $1, 4);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 32:
|
|
|
|
{
|
|
|
|
x86_shift_reg_imm(inst, X86_SHR, $1, 5);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 64:
|
|
|
|
{
|
|
|
|
x86_shift_reg_imm(inst, X86_SHR, $1, 6);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 128:
|
|
|
|
{
|
|
|
|
x86_shift_reg_imm(inst, X86_SHR, $1, 7);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 256:
|
|
|
|
{
|
|
|
|
x86_shift_reg_imm(inst, X86_SHR, $1, 8);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 512:
|
|
|
|
{
|
|
|
|
x86_shift_reg_imm(inst, X86_SHR, $1, 9);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 1024:
|
|
|
|
{
|
|
|
|
x86_shift_reg_imm(inst, X86_SHR, $1, 10);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 2048:
|
|
|
|
{
|
|
|
|
x86_shift_reg_imm(inst, X86_SHR, $1, 11);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 4096:
|
|
|
|
{
|
|
|
|
x86_shift_reg_imm(inst, X86_SHR, $1, 12);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 8192:
|
|
|
|
{
|
|
|
|
x86_shift_reg_imm(inst, X86_SHR, $1, 13);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 16384:
|
|
|
|
{
|
|
|
|
x86_shift_reg_imm(inst, X86_SHR, $1, 14);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 32768:
|
|
|
|
{
|
|
|
|
x86_shift_reg_imm(inst, X86_SHR, $1, 15);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 65536:
|
|
|
|
{
|
|
|
|
x86_shift_reg_imm(inst, X86_SHR, $1, 16);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x00020000:
|
|
|
|
{
|
|
|
|
x86_shift_reg_imm(inst, X86_SHR, $1, 17);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x00040000:
|
|
|
|
{
|
|
|
|
x86_shift_reg_imm(inst, X86_SHR, $1, 18);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x00080000:
|
|
|
|
{
|
|
|
|
x86_shift_reg_imm(inst, X86_SHR, $1, 19);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x00100000:
|
|
|
|
{
|
|
|
|
x86_shift_reg_imm(inst, X86_SHR, $1, 20);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x00200000:
|
|
|
|
{
|
|
|
|
x86_shift_reg_imm(inst, X86_SHR, $1, 21);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x00400000:
|
|
|
|
{
|
|
|
|
x86_shift_reg_imm(inst, X86_SHR, $1, 22);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x00800000:
|
|
|
|
{
|
|
|
|
x86_shift_reg_imm(inst, X86_SHR, $1, 23);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x01000000:
|
|
|
|
{
|
|
|
|
x86_shift_reg_imm(inst, X86_SHR, $1, 24);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x02000000:
|
|
|
|
{
|
|
|
|
x86_shift_reg_imm(inst, X86_SHR, $1, 25);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x04000000:
|
|
|
|
{
|
|
|
|
x86_shift_reg_imm(inst, X86_SHR, $1, 26);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x08000000:
|
|
|
|
{
|
|
|
|
x86_shift_reg_imm(inst, X86_SHR, $1, 27);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x10000000:
|
|
|
|
{
|
|
|
|
x86_shift_reg_imm(inst, X86_SHR, $1, 28);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x20000000:
|
|
|
|
{
|
|
|
|
x86_shift_reg_imm(inst, X86_SHR, $1, 29);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x40000000:
|
|
|
|
{
|
|
|
|
x86_shift_reg_imm(inst, X86_SHR, $1, 30);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case (jit_nint)0x80000000:
|
|
|
|
{
|
|
|
|
x86_shift_reg_imm(inst, X86_SHR, $1, 31);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
{
|
|
|
|
x86_mov_reg_imm(inst, X86_ECX, $2);
|
|
|
|
x86_clear_reg(inst, X86_EDX);
|
|
|
|
x86_div_reg(inst, X86_ECX, 0);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
[reg, reg] -> {
|
|
|
|
unsigned char *patch;
|
|
|
|
x86_alu_reg_reg(inst, X86_OR, $2, $2);
|
|
|
|
patch = inst;
|
|
|
|
x86_branch8(inst, X86_CC_NE, 0, 0);
|
|
|
|
inst = throw_builtin(inst, func, JIT_RESULT_DIVISION_BY_ZERO);
|
|
|
|
x86_patch(patch, inst);
|
|
|
|
x86_clear_reg(inst, X86_EDX);
|
|
|
|
x86_div_reg(inst, $2, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
JIT_OP_IREM: binary, spill_before, more_space
|
|
|
|
[reg, imm] -> {
|
|
|
|
switch($2)
|
|
|
|
{
|
|
|
|
case 0:
|
|
|
|
{
|
|
|
|
inst = throw_builtin(inst, func, JIT_RESULT_DIVISION_BY_ZERO);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 1:
|
|
|
|
{
|
|
|
|
x86_clear_reg(inst, $1);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case -1:
|
|
|
|
{
|
|
|
|
/* Dividing by -1 gives an exception if the argument
|
|
|
|
is minint, or simply gives a remainder of zero */
|
|
|
|
unsigned char *patch = inst;
|
|
|
|
x86_alu_reg_imm(inst, X86_CMP, $1, jit_min_int);
|
|
|
|
x86_branch8(inst, X86_CC_NE, 0, 0);
|
|
|
|
inst = throw_builtin(inst, func, JIT_RESULT_ARITHMETIC);
|
|
|
|
x86_patch(patch, inst);
|
|
|
|
x86_clear_reg(inst, $1);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
{
|
|
|
|
x86_mov_reg_imm(inst, X86_ECX, $2);
|
|
|
|
x86_cdq(inst);
|
|
|
|
x86_div_reg(inst, X86_ECX, 1);
|
|
|
|
/* TODO: rearrange register assignments to avoid the move */
|
|
|
|
x86_mov_reg_reg(inst, X86_EAX, X86_EDX, 4);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
[reg, reg] -> {
|
|
|
|
unsigned char *patch, *patch2;
|
|
|
|
x86_alu_reg_reg(inst, X86_OR, $2, $2);
|
|
|
|
patch = inst;
|
|
|
|
x86_branch8(inst, X86_CC_NE, 0, 0);
|
|
|
|
inst = throw_builtin(inst, func, JIT_RESULT_DIVISION_BY_ZERO);
|
|
|
|
x86_patch(patch, inst);
|
|
|
|
x86_alu_reg_imm(inst, X86_CMP, $2, -1);
|
|
|
|
patch = inst;
|
|
|
|
x86_branch8(inst, X86_CC_NE, 0, 0);
|
|
|
|
x86_alu_reg_imm(inst, X86_CMP, $1, jit_min_int);
|
|
|
|
patch2 = inst;
|
|
|
|
x86_branch8(inst, X86_CC_NE, 0, 0);
|
|
|
|
inst = throw_builtin(inst, func, JIT_RESULT_ARITHMETIC);
|
|
|
|
x86_patch(patch, inst);
|
|
|
|
x86_patch(patch2, inst);
|
|
|
|
x86_cdq(inst);
|
|
|
|
x86_div_reg(inst, $2, 1);
|
|
|
|
x86_mov_reg_reg(inst, X86_EAX, X86_EDX, 4);
|
|
|
|
}
|
|
|
|
|
|
|
|
JIT_OP_IREM_UN: binary, spill_before, more_space
|
|
|
|
[reg, imm] -> {
|
|
|
|
switch($2)
|
|
|
|
{
|
|
|
|
case 0:
|
|
|
|
{
|
|
|
|
inst = throw_builtin(inst, func, JIT_RESULT_DIVISION_BY_ZERO);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 1:
|
|
|
|
{
|
|
|
|
x86_clear_reg(inst, $1);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 2:
|
|
|
|
case 4:
|
|
|
|
case 8:
|
|
|
|
case 16:
|
|
|
|
case 32:
|
|
|
|
case 64:
|
|
|
|
case 128:
|
|
|
|
case 256:
|
|
|
|
case 512:
|
|
|
|
case 1024:
|
|
|
|
case 2048:
|
|
|
|
case 4096:
|
|
|
|
case 8192:
|
|
|
|
case 16384:
|
|
|
|
case 32768:
|
|
|
|
case 65536:
|
|
|
|
case 0x00020000:
|
|
|
|
case 0x00040000:
|
|
|
|
case 0x00080000:
|
|
|
|
case 0x00100000:
|
|
|
|
case 0x00200000:
|
|
|
|
case 0x00400000:
|
|
|
|
case 0x00800000:
|
|
|
|
case 0x01000000:
|
|
|
|
case 0x02000000:
|
|
|
|
case 0x04000000:
|
|
|
|
case 0x08000000:
|
|
|
|
case 0x10000000:
|
|
|
|
case 0x20000000:
|
|
|
|
case 0x40000000:
|
|
|
|
case (jit_nint)0x80000000:
|
|
|
|
{
|
|
|
|
x86_alu_reg_imm(inst, X86_AND, $1, $2 - 1);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
{
|
|
|
|
x86_mov_reg_imm(inst, X86_ECX, $2);
|
|
|
|
x86_clear_reg(inst, X86_EDX);
|
|
|
|
x86_div_reg(inst, X86_ECX, 0);
|
|
|
|
x86_mov_reg_reg(inst, X86_EAX, X86_EDX, 4);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
[reg, reg] -> {
|
|
|
|
unsigned char *patch;
|
|
|
|
x86_alu_reg_reg(inst, X86_OR, $2, $2);
|
|
|
|
patch = inst;
|
|
|
|
x86_branch8(inst, X86_CC_NE, 0, 0);
|
|
|
|
inst = throw_builtin(inst, func, JIT_RESULT_DIVISION_BY_ZERO);
|
|
|
|
x86_patch(patch, inst);
|
|
|
|
x86_clear_reg(inst, X86_EDX);
|
|
|
|
x86_div_reg(inst, $2, 0);
|
|
|
|
x86_mov_reg_reg(inst, X86_EAX, X86_EDX, 4);
|
|
|
|
}
|
|
|
|
|
|
|
|
JIT_OP_INEG: unary
|
|
|
|
[reg] -> {
|
|
|
|
x86_neg_reg(inst, $1);
|
|
|
|
}
|
|
|
|
|
|
|
|
JIT_OP_FADD: binary, stack
|
|
|
|
[freg, freg] -> {
|
|
|
|
x86_fp_op_reg(inst, X86_FADD, 1, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
JIT_OP_FSUB: binary, stack
|
|
|
|
[freg, freg] -> {
|
|
|
|
x86_fp_op_reg(inst, X86_FSUB, 1, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
JIT_OP_FMUL: binary, stack
|
|
|
|
[freg, freg] -> {
|
|
|
|
x86_fp_op_reg(inst, X86_FMUL, 1, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
JIT_OP_FDIV: binary, stack
|
|
|
|
[freg, freg] -> {
|
|
|
|
x86_fp_op_reg(inst, X86_FDIV, 1, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
JIT_OP_FNEG: unary, stack
|
|
|
|
[freg] -> {
|
|
|
|
x86_fchs(inst);
|
|
|
|
}
|
|
|
|
|
|
|
|
JIT_OP_DADD: binary, stack
|
|
|
|
[freg, freg] -> {
|
|
|
|
x86_fp_op_reg(inst, X86_FADD, 1, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
JIT_OP_DSUB: binary, stack
|
|
|
|
[freg, freg] -> {
|
|
|
|
x86_fp_op_reg(inst, X86_FSUB, 1, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
JIT_OP_DMUL: binary, stack
|
|
|
|
[freg, freg] -> {
|
|
|
|
x86_fp_op_reg(inst, X86_FMUL, 1, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
JIT_OP_DDIV: binary, stack
|
|
|
|
[freg, freg] -> {
|
|
|
|
x86_fp_op_reg(inst, X86_FDIV, 1, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
JIT_OP_DNEG: unary, stack
|
|
|
|
[freg] -> {
|
|
|
|
x86_fchs(inst);
|
|
|
|
}
|
|
|
|
|
|
|
|
JIT_OP_NFADD: binary, stack
|
|
|
|
[freg, freg] -> {
|
|
|
|
x86_fp_op_reg(inst, X86_FADD, 1, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
JIT_OP_NFSUB: binary, stack
|
|
|
|
[freg, freg] -> {
|
|
|
|
x86_fp_op_reg(inst, X86_FSUB, 1, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
JIT_OP_NFMUL: binary, stack
|
|
|
|
[freg, freg] -> {
|
|
|
|
x86_fp_op_reg(inst, X86_FMUL, 1, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
JIT_OP_NFDIV: binary, stack
|
|
|
|
[freg, freg] -> {
|
|
|
|
x86_fp_op_reg(inst, X86_FDIV, 1, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
JIT_OP_NFNEG: unary, stack
|
|
|
|
[freg] -> {
|
|
|
|
x86_fchs(inst);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* 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_note
|
|
|
|
[reg] -> {
|
|
|
|
unsigned char *patch;
|
|
|
|
x86_alu_reg_reg(inst, X86_OR, $1, $1);
|
|
|
|
patch = inst;
|
|
|
|
x86_branch8(inst, X86_CC_NE, 0, 0);
|
|
|
|
inst = throw_builtin(inst, func, JIT_RESULT_NULL_REFERENCE);
|
|
|
|
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
|
|
|
|
[] -> {
|
|
|
|
if(jit_value_is_constant(insn->value1))
|
|
|
|
{
|
|
|
|
x86_mov_reg_imm(inst, X86_EAX,
|
|
|
|
((jit_int *)(insn->value1->address))[0]);
|
|
|
|
x86_mov_reg_imm(inst, X86_EDX,
|
|
|
|
((jit_int *)(insn->value1->address))[1]);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
jit_nint offset;
|
|
|
|
_jit_gen_fix_value(insn->value1);
|
|
|
|
offset = insn->value1->frame_offset;
|
|
|
|
x86_mov_reg_membase(inst, X86_EAX, X86_EBP, offset, 4);
|
|
|
|
x86_mov_reg_membase(inst, X86_EDX, X86_EBP, offset + 4, 4);
|
|
|
|
}
|
|
|
|
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 */
|
|
|
|
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)
|
|
|
|
{
|
|
|
|
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 */
|
|
|
|
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: spill_before
|
|
|
|
[] -> {
|
|
|
|
/* TODO */
|
|
|
|
TODO();
|
|
|
|
}
|
|
|
|
|
|
|
|
JIT_OP_COPY_FLOAT32: unary, stack
|
|
|
|
[freg] -> {}
|
|
|
|
|
|
|
|
JIT_OP_COPY_FLOAT64: unary, stack
|
|
|
|
[freg] -> {}
|
|
|
|
|
|
|
|
JIT_OP_COPY_NFLOAT: unary, stack
|
|
|
|
[freg] -> {}
|
|
|
|
|
|
|
|
JIT_OP_COPY_STRUCT: manual
|
|
|
|
[] -> {
|
|
|
|
/* TODO */
|
|
|
|
TODO();
|
|
|
|
}
|
|
|
|
|
|
|
|
JIT_OP_COPY_STORE_BYTE: manual
|
|
|
|
[] -> {
|
|
|
|
unsigned char *inst;
|
|
|
|
int reg;
|
|
|
|
_jit_regs_force_out(gen, insn->dest, 1);
|
|
|
|
_jit_gen_fix_value(insn->dest);
|
|
|
|
if(!(insn->value1->is_constant))
|
|
|
|
{
|
|
|
|
reg = _jit_regs_load_value
|
|
|
|
(gen, insn->value1, 0,
|
|
|
|
(insn->flags & (JIT_INSN_VALUE1_NEXT_USE |
|
|
|
|
JIT_INSN_VALUE1_LIVE)));
|
|
|
|
inst = gen->posn.ptr;
|
|
|
|
if(!jit_cache_check_for_n(&(gen->posn), 32))
|
|
|
|
{
|
|
|
|
jit_cache_mark_full(&(gen->posn));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
inst = mov_membase_reg_byte
|
|
|
|
(inst, X86_EBP, insn->dest->frame_offset,
|
|
|
|
_jit_reg_info[reg].cpu_reg);
|
|
|
|
gen->posn.ptr = inst;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
inst = gen->posn.ptr;
|
|
|
|
if(!jit_cache_check_for_n(&(gen->posn), 32))
|
|
|
|
{
|
|
|
|
jit_cache_mark_full(&(gen->posn));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
x86_mov_membase_imm(inst, X86_EBP, insn->dest->frame_offset,
|
|
|
|
insn->value1->address, 1);
|
|
|
|
gen->posn.ptr = inst;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
JIT_OP_COPY_STORE_SHORT: manual
|
|
|
|
[] -> {
|
|
|
|
unsigned char *inst;
|
|
|
|
int reg;
|
|
|
|
_jit_regs_force_out(gen, insn->dest, 1);
|
|
|
|
_jit_gen_fix_value(insn->dest);
|
|
|
|
if(!(insn->value1->is_constant))
|
|
|
|
{
|
|
|
|
reg = _jit_regs_load_value
|
|
|
|
(gen, insn->value1, 0,
|
|
|
|
(insn->flags & (JIT_INSN_VALUE1_NEXT_USE |
|
|
|
|
JIT_INSN_VALUE1_LIVE)));
|
|
|
|
inst = gen->posn.ptr;
|
|
|
|
if(!jit_cache_check_for_n(&(gen->posn), 32))
|
|
|
|
{
|
|
|
|
jit_cache_mark_full(&(gen->posn));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
x86_mov_membase_reg(inst, X86_EBP, insn->dest->frame_offset,
|
|
|
|
_jit_reg_info[reg].cpu_reg, 2);
|
|
|
|
gen->posn.ptr = inst;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
inst = gen->posn.ptr;
|
|
|
|
if(!jit_cache_check_for_n(&(gen->posn), 32))
|
|
|
|
{
|
|
|
|
jit_cache_mark_full(&(gen->posn));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
x86_mov_membase_imm(inst, X86_EBP, insn->dest->frame_offset,
|
|
|
|
insn->value1->address, 2);
|
|
|
|
gen->posn.ptr = inst;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
JIT_OP_ADDRESS_OF: manual
|
|
|
|
[] -> {
|
|
|
|
unsigned char *inst;
|
|
|
|
int reg;
|
|
|
|
_jit_regs_force_out(gen, insn->value1, 0);
|
|
|
|
_jit_gen_fix_value(insn->value1);
|
|
|
|
inst = gen->posn.ptr;
|
|
|
|
if(!jit_cache_check_for_n(&(gen->posn), 32))
|
|
|
|
{
|
|
|
|
jit_cache_mark_full(&(gen->posn));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
reg = _jit_regs_dest_value(gen, insn->dest);
|
|
|
|
reg = _jit_reg_info[reg].cpu_reg;
|
|
|
|
x86_lea_membase(inst, reg, X86_EBP, insn->value1->frame_offset);
|
|
|
|
gen->posn.ptr = inst;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Stack pushes and pops.
|
|
|
|
*/
|
|
|
|
|
|
|
|
JIT_OP_RETURN_REG: manual
|
|
|
|
[] -> { /* Nothing to do here */ }
|
|
|
|
|
|
|
|
JIT_OP_PUSH_INT: unary_note
|
|
|
|
[imm] -> {
|
|
|
|
x86_push_imm(inst, $1);
|
|
|
|
}
|
|
|
|
[local] -> {
|
|
|
|
x86_push_membase(inst, X86_EBP, $1);
|
|
|
|
}
|
|
|
|
[reg] -> {
|
|
|
|
x86_push_reg(inst, $1);
|
|
|
|
}
|
|
|
|
|
|
|
|
JIT_OP_PUSH_LONG: spill_before
|
|
|
|
[] -> {
|
|
|
|
/* TODO: use 'manual' to avoid register spills */
|
|
|
|
if(jit_value_is_constant(insn->value1))
|
|
|
|
{
|
|
|
|
x86_push_imm(inst, ((jit_int *)(insn->value1->address))[1]);
|
|
|
|
x86_push_imm(inst, ((jit_int *)(insn->value1->address))[0]);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
jit_nint offset;
|
|
|
|
_jit_gen_fix_value(insn->value1);
|
|
|
|
offset = insn->value1->frame_offset;
|
|
|
|
x86_push_membase(inst, X86_EBP, offset + 4);
|
|
|
|
x86_push_membase(inst, X86_EBP, offset);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
JIT_OP_PUSH_FLOAT32: unary_note, stack
|
|
|
|
[imm] -> {
|
|
|
|
jit_int *ptr = (jit_int *)($1);
|
|
|
|
x86_push_imm(inst, ptr[0]);
|
|
|
|
}
|
|
|
|
[local] -> {
|
|
|
|
x86_push_membase(inst, X86_EBP, $1);
|
|
|
|
}
|
|
|
|
[reg] -> {
|
|
|
|
x86_alu_reg_imm(inst, X86_SUB, X86_ESP, sizeof(jit_float32));
|
|
|
|
x86_fst_membase(inst, X86_ESP, 0, 0, 1);
|
|
|
|
_jit_regs_free_reg(gen, reg, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
JIT_OP_PUSH_FLOAT64: unary_note, stack
|
|
|
|
[imm] -> {
|
|
|
|
jit_int *ptr = (jit_int *)($1);
|
|
|
|
x86_push_imm(inst, ptr[1]);
|
|
|
|
x86_push_imm(inst, ptr[0]);
|
|
|
|
}
|
|
|
|
[local] -> {
|
|
|
|
x86_push_membase(inst, X86_EBP, $1 + 4);
|
|
|
|
x86_push_membase(inst, X86_EBP, $1);
|
|
|
|
}
|
|
|
|
[reg] -> {
|
|
|
|
x86_alu_reg_imm(inst, X86_SUB, X86_ESP, sizeof(jit_float64));
|
|
|
|
x86_fst_membase(inst, X86_ESP, 0, 1, 1);
|
|
|
|
_jit_regs_free_reg(gen, reg, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
JIT_OP_PUSH_NFLOAT: unary_note, stack
|
|
|
|
[imm] -> {
|
|
|
|
jit_int *ptr = (jit_int *)($1);
|
|
|
|
if(sizeof(jit_nfloat) != sizeof(jit_float64))
|
|
|
|
{
|
|
|
|
x86_push_imm(inst, ptr[2]);
|
|
|
|
}
|
|
|
|
x86_push_imm(inst, ptr[1]);
|
|
|
|
x86_push_imm(inst, ptr[0]);
|
|
|
|
}
|
|
|
|
[local] -> {
|
|
|
|
if(sizeof(jit_nfloat) != sizeof(jit_float64))
|
|
|
|
{
|
|
|
|
x86_push_membase(inst, X86_EBP, $1 + 8);
|
|
|
|
}
|
|
|
|
x86_push_membase(inst, X86_EBP, $1 + 4);
|
|
|
|
x86_push_membase(inst, X86_EBP, $1);
|
|
|
|
}
|
|
|
|
[freg] -> {
|
|
|
|
if(sizeof(jit_nfloat) != sizeof(jit_float64))
|
|
|
|
{
|
|
|
|
x86_alu_reg_imm(inst, X86_SUB, X86_ESP, sizeof(jit_nfloat));
|
|
|
|
x86_fst80_membase(inst, X86_ESP, 0);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
x86_alu_reg_imm(inst, X86_SUB, X86_ESP, sizeof(jit_float64));
|
|
|
|
x86_fst_membase(inst, X86_ESP, 0, 1, 1);
|
|
|
|
}
|
|
|
|
_jit_regs_free_reg(gen, reg, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
JIT_OP_PUSH_STRUCT: unary_note
|
|
|
|
[reg] -> {
|
|
|
|
/* TODO */
|
|
|
|
TODO();
|
|
|
|
}
|
|
|
|
|
|
|
|
JIT_OP_POP_STACK:
|
|
|
|
[] -> {
|
|
|
|
x86_alu_reg_imm(inst, X86_ADD, X86_ESP, 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:
|
|
|
|
{
|
|
|
|
x86_mov_membase_reg(inst, X86_EBP, offset, X86_EAX, 1);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 2:
|
|
|
|
{
|
|
|
|
x86_mov_membase_reg(inst, X86_EBP, offset, X86_EAX, 2);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 3:
|
|
|
|
{
|
|
|
|
x86_mov_membase_reg(inst, X86_EBP, offset, X86_EAX, 2);
|
|
|
|
x86_shift_reg_imm(inst, X86_EAX, X86_SHR, 16);
|
|
|
|
x86_mov_membase_reg(inst, X86_EBP, offset + 2, X86_EAX, 1);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 4:
|
|
|
|
{
|
|
|
|
x86_mov_membase_reg(inst, X86_EBP, offset, X86_EAX, 4);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 5:
|
|
|
|
{
|
|
|
|
x86_mov_membase_reg(inst, X86_EBP, offset, X86_EAX, 4);
|
|
|
|
x86_mov_membase_reg(inst, X86_EBP, offset + 4, X86_EDX, 1);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 6:
|
|
|
|
{
|
|
|
|
x86_mov_membase_reg(inst, X86_EBP, offset, X86_EAX, 4);
|
|
|
|
x86_mov_membase_reg(inst, X86_EBP, offset + 4, X86_EDX, 2);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 7:
|
|
|
|
{
|
|
|
|
x86_mov_membase_reg(inst, X86_EBP, offset, X86_EAX, 4);
|
|
|
|
x86_mov_membase_reg(inst, X86_EBP, offset + 4, X86_EDX, 2);
|
|
|
|
x86_shift_reg_imm(inst, X86_EDX, X86_SHR, 16);
|
|
|
|
x86_mov_membase_reg(inst, X86_EBP, offset + 6, X86_EDX, 1);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 8:
|
|
|
|
{
|
|
|
|
x86_mov_membase_reg(inst, X86_EBP, offset, X86_EAX, 4);
|
|
|
|
x86_mov_membase_reg(inst, X86_EBP, offset + 4, X86_EDX, 4);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Pointer-relative loads and stores.
|
|
|
|
*/
|
|
|
|
|
|
|
|
JIT_OP_LOAD_RELATIVE_SBYTE: unary
|
|
|
|
[reg] -> {
|
|
|
|
x86_widen_membase(inst, $1, $1, insn->value2->address, 1, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
JIT_OP_LOAD_RELATIVE_UBYTE: unary
|
|
|
|
[reg] -> {
|
|
|
|
x86_widen_membase(inst, $1, $1, insn->value2->address, 0, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
JIT_OP_LOAD_RELATIVE_SHORT: unary
|
|
|
|
[reg] -> {
|
|
|
|
x86_widen_membase(inst, $1, $1, insn->value2->address, 1, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
JIT_OP_LOAD_RELATIVE_USHORT: unary
|
|
|
|
[reg] -> {
|
|
|
|
x86_widen_membase(inst, $1, $1, insn->value2->address, 0, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
JIT_OP_LOAD_RELATIVE_INT: unary
|
|
|
|
[reg] -> {
|
|
|
|
x86_mov_reg_membase(inst, $1, $1, insn->value2->address, 4);
|
|
|
|
}
|
|
|
|
|
|
|
|
JIT_OP_LOAD_RELATIVE_LONG: manual
|
|
|
|
[] -> {
|
|
|
|
unsigned char *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;
|
|
|
|
inst = gen->posn.ptr;
|
|
|
|
if(!jit_cache_check_for_n(&(gen->posn), 32))
|
|
|
|
{
|
|
|
|
jit_cache_mark_full(&(gen->posn));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
x86_mov_reg_membase(inst, reg2, reg, insn->value2->address, 4);
|
|
|
|
x86_mov_reg_membase(inst, reg3, reg, insn->value2->address + 4, 4);
|
|
|
|
x86_mov_membase_reg(inst, X86_EBP, frame_offset, reg2, 4);
|
|
|
|
x86_mov_membase_reg(inst, X86_EBP, frame_offset + 4, reg3, 4);
|
|
|
|
insn->dest->in_frame = 1;
|
|
|
|
gen->posn.ptr = inst;
|
|
|
|
}
|
|
|
|
|
|
|
|
JIT_OP_LOAD_RELATIVE_FLOAT32: manual
|
|
|
|
[] -> {
|
|
|
|
unsigned char *inst;
|
|
|
|
int reg = _jit_regs_load_value
|
|
|
|
(gen, insn->value1, 0,
|
|
|
|
(insn->flags & (JIT_INSN_VALUE1_NEXT_USE |
|
|
|
|
JIT_INSN_VALUE1_LIVE)));
|
|
|
|
_jit_regs_new_top(gen, insn->dest, 8);
|
|
|
|
inst = gen->posn.ptr;
|
|
|
|
if(!jit_cache_check_for_n(&(gen->posn), 32))
|
|
|
|
{
|
|
|
|
jit_cache_mark_full(&(gen->posn));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
reg = _jit_reg_info[reg].cpu_reg;
|
|
|
|
x86_fld_membase(inst, reg, insn->value2->address, 0);
|
|
|
|
gen->posn.ptr = inst;
|
|
|
|
}
|
|
|
|
|
|
|
|
JIT_OP_LOAD_RELATIVE_FLOAT64: manual
|
|
|
|
[] -> {
|
|
|
|
unsigned char *inst;
|
|
|
|
int reg = _jit_regs_load_value
|
|
|
|
(gen, insn->value1, 0,
|
|
|
|
(insn->flags & (JIT_INSN_VALUE1_NEXT_USE |
|
|
|
|
JIT_INSN_VALUE1_LIVE)));
|
|
|
|
_jit_regs_new_top(gen, insn->dest, 8);
|
|
|
|
inst = gen->posn.ptr;
|
|
|
|
if(!jit_cache_check_for_n(&(gen->posn), 32))
|
|
|
|
{
|
|
|
|
jit_cache_mark_full(&(gen->posn));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
reg = _jit_reg_info[reg].cpu_reg;
|
|
|
|
x86_fld_membase(inst, reg, insn->value2->address, 1);
|
|
|
|
gen->posn.ptr = inst;
|
|
|
|
}
|
|
|
|
|
|
|
|
JIT_OP_LOAD_RELATIVE_NFLOAT: manual
|
|
|
|
[] -> {
|
|
|
|
unsigned char *inst;
|
|
|
|
int reg = _jit_regs_load_value
|
|
|
|
(gen, insn->value1, 0,
|
|
|
|
(insn->flags & (JIT_INSN_VALUE1_NEXT_USE |
|
|
|
|
JIT_INSN_VALUE1_LIVE)));
|
|
|
|
_jit_regs_new_top(gen, insn->dest, 8);
|
|
|
|
inst = gen->posn.ptr;
|
|
|
|
if(!jit_cache_check_for_n(&(gen->posn), 32))
|
|
|
|
{
|
|
|
|
jit_cache_mark_full(&(gen->posn));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
reg = _jit_reg_info[reg].cpu_reg;
|
|
|
|
if(sizeof(jit_nfloat) != sizeof(jit_float64))
|
|
|
|
{
|
|
|
|
x86_fld80_membase(inst, reg, insn->value2->address);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
x86_fld_membase(inst, reg, insn->value2->address, 1);
|
|
|
|
}
|
|
|
|
gen->posn.ptr = inst;
|
|
|
|
}
|
|
|
|
|
|
|
|
JIT_OP_LOAD_RELATIVE_STRUCT: manual
|
|
|
|
[] -> {
|
|
|
|
/* TODO */
|
|
|
|
TODO();
|
|
|
|
}
|
|
|
|
|
|
|
|
JIT_OP_STORE_RELATIVE_BYTE: manual
|
|
|
|
[] -> {
|
|
|
|
unsigned char *inst;
|
|
|
|
int reg = _jit_regs_load_value
|
|
|
|
(gen, insn->dest, 0,
|
|
|
|
(insn->flags & (JIT_INSN_DEST_NEXT_USE |
|
|
|
|
JIT_INSN_DEST_LIVE)));
|
|
|
|
if(!(insn->value1->is_constant))
|
|
|
|
{
|
|
|
|
int reg2 = _jit_regs_load_value
|
|
|
|
(gen, insn->value1, 0,
|
|
|
|
(insn->flags & (JIT_INSN_VALUE1_NEXT_USE |
|
|
|
|
JIT_INSN_VALUE1_LIVE)));
|
|
|
|
inst = gen->posn.ptr;
|
|
|
|
if(!jit_cache_check_for_n(&(gen->posn), 32))
|
|
|
|
{
|
|
|
|
jit_cache_mark_full(&(gen->posn));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
reg = _jit_reg_info[reg].cpu_reg;
|
|
|
|
reg2 = _jit_reg_info[reg2].cpu_reg;
|
|
|
|
inst = mov_membase_reg_byte
|
|
|
|
(inst, reg, insn->value2->address, reg2);
|
|
|
|
gen->posn.ptr = inst;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
inst = gen->posn.ptr;
|
|
|
|
if(!jit_cache_check_for_n(&(gen->posn), 32))
|
|
|
|
{
|
|
|
|
jit_cache_mark_full(&(gen->posn));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
reg = _jit_reg_info[reg].cpu_reg;
|
|
|
|
x86_mov_membase_imm(inst, reg, insn->value2->address,
|
|
|
|
insn->value1->address, 1);
|
|
|
|
gen->posn.ptr = inst;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
JIT_OP_STORE_RELATIVE_SHORT: manual
|
|
|
|
[] -> {
|
|
|
|
unsigned char *inst;
|
|
|
|
int reg = _jit_regs_load_value
|
|
|
|
(gen, insn->dest, 0,
|
|
|
|
(insn->flags & (JIT_INSN_DEST_NEXT_USE |
|
|
|
|
JIT_INSN_DEST_LIVE)));
|
|
|
|
if(!(insn->value1->is_constant))
|
|
|
|
{
|
|
|
|
int reg2 = _jit_regs_load_value
|
|
|
|
(gen, insn->value1, 0,
|
|
|
|
(insn->flags & (JIT_INSN_VALUE1_NEXT_USE |
|
|
|
|
JIT_INSN_VALUE1_LIVE)));
|
|
|
|
inst = gen->posn.ptr;
|
|
|
|
if(!jit_cache_check_for_n(&(gen->posn), 32))
|
|
|
|
{
|
|
|
|
jit_cache_mark_full(&(gen->posn));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
reg = _jit_reg_info[reg].cpu_reg;
|
|
|
|
reg2 = _jit_reg_info[reg2].cpu_reg;
|
|
|
|
x86_mov_membase_reg(inst, reg, insn->value2->address, reg2, 2);
|
|
|
|
gen->posn.ptr = inst;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
inst = gen->posn.ptr;
|
|
|
|
if(!jit_cache_check_for_n(&(gen->posn), 32))
|
|
|
|
{
|
|
|
|
jit_cache_mark_full(&(gen->posn));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
reg = _jit_reg_info[reg].cpu_reg;
|
|
|
|
x86_mov_membase_imm(inst, reg, insn->value2->address,
|
|
|
|
insn->value1->address, 2);
|
|
|
|
gen->posn.ptr = inst;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
JIT_OP_STORE_RELATIVE_INT: manual
|
|
|
|
[] -> {
|
|
|
|
unsigned char *inst;
|
|
|
|
int reg = _jit_regs_load_value
|
|
|
|
(gen, insn->dest, 0,
|
|
|
|
(insn->flags & (JIT_INSN_DEST_NEXT_USE |
|
|
|
|
JIT_INSN_DEST_LIVE)));
|
|
|
|
if(!(insn->value1->is_constant))
|
|
|
|
{
|
|
|
|
int reg2 = _jit_regs_load_value
|
|
|
|
(gen, insn->value1, 0,
|
|
|
|
(insn->flags & (JIT_INSN_VALUE1_NEXT_USE |
|
|
|
|
JIT_INSN_VALUE1_LIVE)));
|
|
|
|
inst = gen->posn.ptr;
|
|
|
|
if(!jit_cache_check_for_n(&(gen->posn), 32))
|
|
|
|
{
|
|
|
|
jit_cache_mark_full(&(gen->posn));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
reg = _jit_reg_info[reg].cpu_reg;
|
|
|
|
reg2 = _jit_reg_info[reg2].cpu_reg;
|
|
|
|
x86_mov_membase_reg(inst, reg, insn->value2->address, reg2, 4);
|
|
|
|
gen->posn.ptr = inst;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
inst = gen->posn.ptr;
|
|
|
|
if(!jit_cache_check_for_n(&(gen->posn), 32))
|
|
|
|
{
|
|
|
|
jit_cache_mark_full(&(gen->posn));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
reg = _jit_reg_info[reg].cpu_reg;
|
|
|
|
x86_mov_membase_imm(inst, reg, insn->value2->address,
|
|
|
|
insn->value1->address, 4);
|
|
|
|
gen->posn.ptr = inst;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
JIT_OP_STORE_RELATIVE_LONG: manual
|
|
|
|
[] -> {
|
|
|
|
unsigned char *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;
|
|
|
|
if(!(insn->value1->is_constant))
|
|
|
|
{
|
|
|
|
_jit_regs_get_reg_pair(gen, reg, -1, -1, ®2, ®3);
|
|
|
|
_jit_gen_fix_value(insn->value1);
|
|
|
|
inst = gen->posn.ptr;
|
|
|
|
if(!jit_cache_check_for_n(&(gen->posn), 32))
|
|
|
|
{
|
|
|
|
jit_cache_mark_full(&(gen->posn));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
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;
|
|
|
|
x86_mov_reg_membase(inst, reg2, X86_EBP, frame_offset, 4);
|
|
|
|
x86_mov_reg_membase(inst, reg3, X86_EBP, frame_offset + 4, 4);
|
|
|
|
x86_mov_membase_reg(inst, reg, insn->value2->address, reg2, 4);
|
|
|
|
x86_mov_membase_reg(inst, reg, insn->value2->address + 4, reg3, 4);
|
|
|
|
gen->posn.ptr = inst;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
jit_long const_value = jit_value_get_long_constant(insn->value1);
|
|
|
|
inst = gen->posn.ptr;
|
|
|
|
if(!jit_cache_check_for_n(&(gen->posn), 32))
|
|
|
|
{
|
|
|
|
jit_cache_mark_full(&(gen->posn));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
reg = _jit_reg_info[reg].cpu_reg;
|
|
|
|
x86_mov_membase_imm
|
|
|
|
(inst, reg, insn->value2->address,
|
|
|
|
(jit_int)(const_value & jit_max_uint), 4);
|
|
|
|
x86_mov_membase_imm
|
|
|
|
(inst, reg, insn->value2->address,
|
|
|
|
(jit_int)((const_value >> 32) & jit_max_uint), 4);
|
|
|
|
gen->posn.ptr = inst;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
JIT_OP_STORE_RELATIVE_FLOAT32: manual
|
|
|
|
[] -> {
|
|
|
|
unsigned char *inst;
|
|
|
|
int reg = _jit_regs_load_value
|
|
|
|
(gen, insn->dest, 0,
|
|
|
|
(insn->flags & (JIT_INSN_DEST_NEXT_USE |
|
|
|
|
JIT_INSN_DEST_LIVE)));
|
|
|
|
if(!(insn->value1->is_constant))
|
|
|
|
{
|
|
|
|
_jit_regs_load_to_top
|
|
|
|
(gen, insn->value1,
|
|
|
|
(insn->flags & (JIT_INSN_VALUE1_NEXT_USE |
|
|
|
|
JIT_INSN_VALUE1_LIVE)), 8);
|
|
|
|
inst = gen->posn.ptr;
|
|
|
|
if(!jit_cache_check_for_n(&(gen->posn), 32))
|
|
|
|
{
|
|
|
|
jit_cache_mark_full(&(gen->posn));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
reg = _jit_reg_info[reg].cpu_reg;
|
|
|
|
x86_fst_membase(inst, reg, insn->value2->address, 0, 1);
|
|
|
|
gen->posn.ptr = inst;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
inst = gen->posn.ptr;
|
|
|
|
if(!jit_cache_check_for_n(&(gen->posn), 32))
|
|
|
|
{
|
|
|
|
jit_cache_mark_full(&(gen->posn));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
reg = _jit_reg_info[reg].cpu_reg;
|
|
|
|
x86_mov_membase_imm(inst, reg, insn->value2->address,
|
|
|
|
*((int *)(insn->value1->address)), 4);
|
|
|
|
gen->posn.ptr = inst;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
JIT_OP_STORE_RELATIVE_FLOAT64: manual
|
|
|
|
[] -> {
|
|
|
|
unsigned char *inst;
|
|
|
|
int reg = _jit_regs_load_value
|
|
|
|
(gen, insn->dest, 0,
|
|
|
|
(insn->flags & (JIT_INSN_DEST_NEXT_USE |
|
|
|
|
JIT_INSN_DEST_LIVE)));
|
|
|
|
if(!(insn->value1->is_constant))
|
|
|
|
{
|
|
|
|
_jit_regs_load_to_top
|
|
|
|
(gen, insn->value1,
|
|
|
|
(insn->flags & (JIT_INSN_VALUE1_NEXT_USE |
|
|
|
|
JIT_INSN_VALUE1_LIVE)), 8);
|
|
|
|
inst = gen->posn.ptr;
|
|
|
|
if(!jit_cache_check_for_n(&(gen->posn), 32))
|
|
|
|
{
|
|
|
|
jit_cache_mark_full(&(gen->posn));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
reg = _jit_reg_info[reg].cpu_reg;
|
|
|
|
x86_fst_membase(inst, reg, insn->value2->address, 1, 1);
|
|
|
|
gen->posn.ptr = inst;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
inst = gen->posn.ptr;
|
|
|
|
if(!jit_cache_check_for_n(&(gen->posn), 32))
|
|
|
|
{
|
|
|
|
jit_cache_mark_full(&(gen->posn));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
reg = _jit_reg_info[reg].cpu_reg;
|
|
|
|
x86_mov_membase_imm(inst, reg, insn->value2->address,
|
|
|
|
((int *)(insn->value1->address))[0], 4);
|
|
|
|
x86_mov_membase_imm(inst, reg, insn->value2->address + 4,
|
|
|
|
((int *)(insn->value1->address))[1], 4);
|
|
|
|
gen->posn.ptr = inst;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
JIT_OP_STORE_RELATIVE_NFLOAT: manual
|
|
|
|
[] -> {
|
|
|
|
unsigned char *inst;
|
|
|
|
int reg = _jit_regs_load_value
|
|
|
|
(gen, insn->dest, 0,
|
|
|
|
(insn->flags & (JIT_INSN_DEST_NEXT_USE |
|
|
|
|
JIT_INSN_DEST_LIVE)));
|
|
|
|
if(!(insn->value1->is_constant))
|
|
|
|
{
|
|
|
|
_jit_regs_load_to_top
|
|
|
|
(gen, insn->value1,
|
|
|
|
(insn->flags & (JIT_INSN_VALUE1_NEXT_USE |
|
|
|
|
JIT_INSN_VALUE1_LIVE)), 8);
|
|
|
|
inst = gen->posn.ptr;
|
|
|
|
if(!jit_cache_check_for_n(&(gen->posn), 32))
|
|
|
|
{
|
|
|
|
jit_cache_mark_full(&(gen->posn));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
reg = _jit_reg_info[reg].cpu_reg;
|
|
|
|
if(sizeof(jit_nfloat) != sizeof(jit_float64))
|
|
|
|
{
|
|
|
|
x86_fst80_membase(inst, reg, insn->value2->address);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
x86_fst_membase(inst, reg, insn->value2->address, 1, 1);
|
|
|
|
}
|
|
|
|
gen->posn.ptr = inst;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
inst = gen->posn.ptr;
|
|
|
|
if(!jit_cache_check_for_n(&(gen->posn), 32))
|
|
|
|
{
|
|
|
|
jit_cache_mark_full(&(gen->posn));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
reg = _jit_reg_info[reg].cpu_reg;
|
|
|
|
x86_mov_membase_imm(inst, reg, insn->value2->address,
|
|
|
|
((int *)(insn->value1->address))[0], 4);
|
|
|
|
x86_mov_membase_imm(inst, reg, insn->value2->address + 4,
|
|
|
|
((int *)(insn->value1->address))[1], 4);
|
|
|
|
if(sizeof(jit_nfloat) != sizeof(jit_float64))
|
|
|
|
{
|
|
|
|
x86_mov_membase_imm(inst, reg, insn->value2->address + 8,
|
|
|
|
((int *)(insn->value1->address))[2], 4);
|
|
|
|
}
|
|
|
|
gen->posn.ptr = inst;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
JIT_OP_STORE_RELATIVE_STRUCT: manual
|
|
|
|
[] -> {
|
|
|
|
/* TODO */
|
|
|
|
TODO();
|
|
|
|
}
|
|
|
|
|
|
|
|
JIT_OP_ADD_RELATIVE: unary
|
|
|
|
[reg] -> {
|
|
|
|
if(insn->value2->address != 0)
|
|
|
|
{
|
|
|
|
x86_alu_reg_imm(inst, X86_ADD, $1, insn->value2->address);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Array element loads and stores.
|
|
|
|
*/
|
|
|
|
|
|
|
|
JIT_OP_LOAD_ELEMENT_SBYTE: binary
|
|
|
|
[reg, reg] -> {
|
|
|
|
x86_widen_memindex(inst, $1, $1, 0, $2, 0, 1, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
JIT_OP_LOAD_ELEMENT_UBYTE: binary
|
|
|
|
[reg, reg] -> {
|
|
|
|
x86_widen_memindex(inst, $1, $1, 0, $2, 0, 0, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
JIT_OP_LOAD_ELEMENT_SHORT: binary
|
|
|
|
[reg, reg] -> {
|
|
|
|
x86_widen_memindex(inst, $1, $1, 0, $2, 1, 1, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
JIT_OP_LOAD_ELEMENT_USHORT: binary
|
|
|
|
[reg, reg] -> {
|
|
|
|
x86_widen_memindex(inst, $1, $1, 0, $2, 1, 0, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
JIT_OP_LOAD_ELEMENT_INT: binary
|
|
|
|
[reg, reg] -> {
|
|
|
|
x86_mov_reg_memindex(inst, $1, $1, 0, $2, 2, 4);
|
|
|
|
}
|
|
|
|
|
|
|
|
JIT_OP_LOAD_ELEMENT_LONG: manual
|
|
|
|
[] -> {
|
|
|
|
unsigned char *inst;
|
|
|
|
int reg, reg2, temp_reg, offset;
|
|
|
|
_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)));
|
|
|
|
reg2 = _jit_regs_load_value
|
|
|
|
(gen, insn->value2, 1,
|
|
|
|
(insn->flags & (JIT_INSN_VALUE2_NEXT_USE |
|
|
|
|
JIT_INSN_VALUE2_LIVE)));
|
|
|
|
_jit_regs_get_reg_pair(gen, reg, reg2, -1, &temp_reg, 0);
|
|
|
|
offset = insn->dest->frame_offset;
|
|
|
|
inst = gen->posn.ptr;
|
|
|
|
if(!jit_cache_check_for_n(&(gen->posn), 32))
|
|
|
|
{
|
|
|
|
jit_cache_mark_full(&(gen->posn));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
reg = _jit_reg_info[reg].cpu_reg;
|
|
|
|
reg2 = _jit_reg_info[reg2].cpu_reg;
|
|
|
|
temp_reg = _jit_reg_info[temp_reg].cpu_reg;
|
|
|
|
x86_mov_reg_memindex(inst, temp_reg, reg, 0, reg2, 3, 4);
|
|
|
|
x86_mov_reg_memindex(inst, reg2, reg, 4, reg2, 3, 4);
|
|
|
|
x86_mov_membase_reg(inst, X86_EBP, offset, temp_reg, 4);
|
|
|
|
x86_mov_membase_reg(inst, X86_EBP, offset + 4, reg2, 4);
|
|
|
|
gen->posn.ptr = inst;
|
|
|
|
}
|
|
|
|
|
|
|
|
JIT_OP_LOAD_ELEMENT_FLOAT32: manual
|
|
|
|
[] -> {
|
|
|
|
/* TODO */
|
|
|
|
TODO();
|
|
|
|
}
|
|
|
|
|
|
|
|
JIT_OP_LOAD_ELEMENT_FLOAT64: manual
|
|
|
|
[] -> {
|
|
|
|
/* TODO */
|
|
|
|
TODO();
|
|
|
|
}
|
|
|
|
|
|
|
|
JIT_OP_LOAD_ELEMENT_NFLOAT: manual
|
|
|
|
[] -> {
|
|
|
|
/* TODO */
|
|
|
|
TODO();
|
|
|
|
}
|
|
|
|
|
|
|
|
JIT_OP_STORE_ELEMENT_BYTE: ternary
|
|
|
|
[reg, reg, reg] -> {
|
|
|
|
inst = mov_memindex_reg_byte(inst, $1, 0, $2, $3);
|
|
|
|
}
|
|
|
|
|
|
|
|
JIT_OP_STORE_ELEMENT_SHORT: ternary
|
|
|
|
[reg, reg, reg] -> {
|
|
|
|
x86_mov_memindex_reg(inst, $1, 0, $2, 1, $3, 2);
|
|
|
|
}
|
|
|
|
|
|
|
|
JIT_OP_STORE_ELEMENT_INT: ternary
|
|
|
|
[reg, reg, reg] -> {
|
|
|
|
x86_mov_memindex_reg(inst, $1, 0, $2, 2, $3, 4);
|
|
|
|
}
|
|
|
|
|
|
|
|
JIT_OP_STORE_ELEMENT_LONG: manual
|
|
|
|
[] -> {
|
|
|
|
/* TODO */
|
|
|
|
TODO();
|
|
|
|
}
|
|
|
|
|
|
|
|
JIT_OP_STORE_ELEMENT_FLOAT32: ternary
|
|
|
|
[reg, reg, freg] -> {
|
|
|
|
/* TODO */
|
|
|
|
TODO();
|
|
|
|
}
|
|
|
|
|
|
|
|
JIT_OP_STORE_ELEMENT_FLOAT64: ternary
|
|
|
|
[reg, reg, freg] -> {
|
|
|
|
/* TODO */
|
|
|
|
TODO();
|
|
|
|
}
|
|
|
|
|
|
|
|
JIT_OP_STORE_ELEMENT_NFLOAT: ternary
|
|
|
|
[reg, reg, freg] -> {
|
|
|
|
/* TODO */
|
|
|
|
TODO();
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Block operations.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
#define JIT_OP_MEMCPY 0x0194
|
|
|
|
#define JIT_OP_MEMMOVE 0x0195
|
|
|
|
#define JIT_OP_MEMSET 0x0196
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Allocate memory from the stack.
|
|
|
|
*/
|
|
|
|
|
|
|
|
JIT_OP_ALLOCA: unary
|
|
|
|
[reg] -> {
|
|
|
|
x86_alu_reg_imm(inst, X86_ADD, $1, 15);
|
|
|
|
x86_alu_reg_imm(inst, X86_AND, $1, ~15);
|
|
|
|
x86_alu_reg_reg(inst, X86_SUB, X86_ESP, $1);
|
|
|
|
x86_mov_reg_reg(inst, $1, X86_ESP, 4);
|
|
|
|
}
|