/* * 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_note [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_note, stack, only [freg] -> { inst = jump_to_epilog(gen, inst, block); } JIT_OP_RETURN_FLOAT64: unary_note, stack, only [freg] -> { inst = jump_to_epilog(gen, inst, block); } JIT_OP_RETURN_NFLOAT: unary_note, 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); }