|
|
| version 1.1.1.1, 2012/02/21 23:05:52 | version 1.1.1.2, 2012/02/21 23:50:25 |
|---|---|
| Line 1 | Line 1 |
| /* | /* |
| * Stack-less Just-In-Time compiler | * Stack-less Just-In-Time compiler |
| * | * |
| * Copyright 2009-2010 Zoltan Herczeg (hzmester@freemail.hu). All rights reserved. | * Copyright 2009-2012 Zoltan Herczeg (hzmester@freemail.hu). All rights reserved. |
| * | * |
| * Redistribution and use in source and binary forms, with or without modification, are | * Redistribution and use in source and binary forms, with or without modification, are |
| * permitted provided that the following conditions are met: | * permitted provided that the following conditions are met: |
| Line 26 | Line 26 |
| SLJIT_API_FUNC_ATTRIBUTE SLJIT_CONST char* sljit_get_platform_name() | SLJIT_API_FUNC_ATTRIBUTE SLJIT_CONST char* sljit_get_platform_name() |
| { | { |
| #if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) | return "x86" SLJIT_CPUINFO; |
| return "x86-32"; | |
| #else | |
| return "x86-64"; | |
| #endif | |
| } | } |
| /* | /* |
| Line 80 static SLJIT_CONST sljit_ub reg_map[SLJIT_NO_REGISTERS | Line 76 static SLJIT_CONST sljit_ub reg_map[SLJIT_NO_REGISTERS |
| p = SLJIT_MEM1(SLJIT_LOCALS_REG); \ | p = SLJIT_MEM1(SLJIT_LOCALS_REG); \ |
| do; \ | do; \ |
| } \ | } \ |
| else if (p >= SLJIT_GENERAL_EREG1 && p <= SLJIT_GENERAL_EREG2) { \ | else if (p >= SLJIT_SAVED_EREG1 && p <= SLJIT_SAVED_EREG2) { \ |
| w = compiler->generals_start + (p - SLJIT_GENERAL_EREG1) * sizeof(sljit_w); \ | w = compiler->saveds_start + (p - SLJIT_SAVED_EREG1) * sizeof(sljit_w); \ |
| p = SLJIT_MEM1(SLJIT_LOCALS_REG); \ | p = SLJIT_MEM1(SLJIT_LOCALS_REG); \ |
| do; \ | do; \ |
| } | } |
| Line 95 static SLJIT_CONST sljit_ub reg_map[SLJIT_NO_REGISTERS | Line 91 static SLJIT_CONST sljit_ub reg_map[SLJIT_NO_REGISTERS |
| /* Note: r12 & 0x7 == 0b100, which decoded as SIB byte present | /* Note: r12 & 0x7 == 0b100, which decoded as SIB byte present |
| Note: avoid to use r12 and r13 for memory addessing | Note: avoid to use r12 and r13 for memory addessing |
| therefore r12 is better for GENERAL_EREG than GENERAL_REG. */ | therefore r12 is better for SAVED_EREG than SAVED_REG. */ |
| #ifndef _WIN64 | #ifndef _WIN64 |
| /* 1st passed in rdi, 2nd argument passed in rsi, 3rd in rdx. */ | /* 1st passed in rdi, 2nd argument passed in rsi, 3rd in rdx. */ |
| static SLJIT_CONST sljit_ub reg_map[SLJIT_NO_REGISTERS + 4] = { | static SLJIT_CONST sljit_ub reg_map[SLJIT_NO_REGISTERS + 4] = { |
| Line 474 static void SLJIT_CALL sljit_touch_stack(sljit_w local | Line 470 static void SLJIT_CALL sljit_touch_stack(sljit_w local |
| #include "sljitNativeX86_64.c" | #include "sljitNativeX86_64.c" |
| #endif | #endif |
| SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_op0(struct sljit_compiler *compiler, int op) | |
| { | |
| sljit_ub *buf; | |
| CHECK_ERROR(); | |
| check_sljit_emit_op0(compiler, op); | |
| op = GET_OPCODE(op); | |
| switch (op) { | |
| case SLJIT_BREAKPOINT: | |
| buf = (sljit_ub*)ensure_buf(compiler, 1 + 1); | |
| FAIL_IF(!buf); | |
| INC_SIZE(1); | |
| *buf = 0xcc; | |
| break; | |
| case SLJIT_NOP: | |
| buf = (sljit_ub*)ensure_buf(compiler, 1 + 1); | |
| FAIL_IF(!buf); | |
| INC_SIZE(1); | |
| *buf = 0x90; | |
| break; | |
| } | |
| return SLJIT_SUCCESS; | |
| } | |
| static int emit_mov(struct sljit_compiler *compiler, | static int emit_mov(struct sljit_compiler *compiler, |
| int dst, sljit_w dstw, | int dst, sljit_w dstw, |
| int src, sljit_w srcw) | int src, sljit_w srcw) |
| Line 568 static int emit_mov(struct sljit_compiler *compiler, | Line 538 static int emit_mov(struct sljit_compiler *compiler, |
| #define EMIT_MOV(compiler, dst, dstw, src, srcw) \ | #define EMIT_MOV(compiler, dst, dstw, src, srcw) \ |
| FAIL_IF(emit_mov(compiler, dst, dstw, src, srcw)); | FAIL_IF(emit_mov(compiler, dst, dstw, src, srcw)); |
| SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_op0(struct sljit_compiler *compiler, int op) | |
| { | |
| sljit_ub *buf; | |
| #if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) | |
| int size; | |
| #endif | |
| CHECK_ERROR(); | |
| check_sljit_emit_op0(compiler, op); | |
| switch (GET_OPCODE(op)) { | |
| case SLJIT_BREAKPOINT: | |
| buf = (sljit_ub*)ensure_buf(compiler, 1 + 1); | |
| FAIL_IF(!buf); | |
| INC_SIZE(1); | |
| *buf = 0xcc; | |
| break; | |
| case SLJIT_NOP: | |
| buf = (sljit_ub*)ensure_buf(compiler, 1 + 1); | |
| FAIL_IF(!buf); | |
| INC_SIZE(1); | |
| *buf = 0x90; | |
| break; | |
| case SLJIT_UMUL: | |
| case SLJIT_SMUL: | |
| case SLJIT_UDIV: | |
| case SLJIT_SDIV: | |
| compiler->flags_saved = 0; | |
| #if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) | |
| #ifdef _WIN64 | |
| SLJIT_COMPILE_ASSERT( | |
| reg_map[SLJIT_TEMPORARY_REG1] == 0 | |
| && reg_map[SLJIT_TEMPORARY_REG2] == 2 | |
| && reg_map[TMP_REGISTER] > 7, | |
| invalid_register_assignment_for_div_mul); | |
| #else | |
| SLJIT_COMPILE_ASSERT( | |
| reg_map[SLJIT_TEMPORARY_REG1] == 0 | |
| && reg_map[SLJIT_TEMPORARY_REG2] < 7 | |
| && reg_map[TMP_REGISTER] == 2, | |
| invalid_register_assignment_for_div_mul); | |
| #endif | |
| compiler->mode32 = op & SLJIT_INT_OP; | |
| #endif | |
| op = GET_OPCODE(op); | |
| if (op == SLJIT_UDIV) { | |
| #if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) || defined(_WIN64) | |
| EMIT_MOV(compiler, TMP_REGISTER, 0, SLJIT_TEMPORARY_REG2, 0); | |
| buf = emit_x86_instruction(compiler, 1, SLJIT_TEMPORARY_REG2, 0, SLJIT_TEMPORARY_REG2, 0); | |
| #else | |
| buf = emit_x86_instruction(compiler, 1, TMP_REGISTER, 0, TMP_REGISTER, 0); | |
| #endif | |
| FAIL_IF(!buf); | |
| *buf = 0x33; | |
| } | |
| if (op == SLJIT_SDIV) { | |
| #if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) || defined(_WIN64) | |
| EMIT_MOV(compiler, TMP_REGISTER, 0, SLJIT_TEMPORARY_REG2, 0); | |
| #endif | |
| /* CDQ instruction */ | |
| #if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) | |
| buf = (sljit_ub*)ensure_buf(compiler, 1 + 1); | |
| FAIL_IF(!buf); | |
| INC_SIZE(1); | |
| *buf = 0x99; | |
| #else | |
| if (compiler->mode32) { | |
| buf = (sljit_ub*)ensure_buf(compiler, 1 + 1); | |
| FAIL_IF(!buf); | |
| INC_SIZE(1); | |
| *buf = 0x99; | |
| } else { | |
| buf = (sljit_ub*)ensure_buf(compiler, 1 + 2); | |
| FAIL_IF(!buf); | |
| INC_SIZE(2); | |
| *buf++ = REX_W; | |
| *buf = 0x99; | |
| } | |
| #endif | |
| } | |
| #if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) | |
| buf = (sljit_ub*)ensure_buf(compiler, 1 + 2); | |
| FAIL_IF(!buf); | |
| INC_SIZE(2); | |
| *buf++ = 0xf7; | |
| *buf = 0xc0 | ((op >= SLJIT_UDIV) ? reg_map[TMP_REGISTER] : reg_map[SLJIT_TEMPORARY_REG2]); | |
| #else | |
| #ifdef _WIN64 | |
| size = (!compiler->mode32 || op >= SLJIT_UDIV) ? 3 : 2; | |
| #else | |
| size = (!compiler->mode32) ? 3 : 2; | |
| #endif | |
| buf = (sljit_ub*)ensure_buf(compiler, 1 + size); | |
| FAIL_IF(!buf); | |
| INC_SIZE(size); | |
| #ifdef _WIN64 | |
| if (!compiler->mode32) | |
| *buf++ = REX_W | ((op >= SLJIT_UDIV) ? REX_B : 0); | |
| else if (op >= SLJIT_UDIV) | |
| *buf++ = REX_B; | |
| *buf++ = 0xf7; | |
| *buf = 0xc0 | ((op >= SLJIT_UDIV) ? reg_lmap[TMP_REGISTER] : reg_lmap[SLJIT_TEMPORARY_REG2]); | |
| #else | |
| if (!compiler->mode32) | |
| *buf++ = REX_W; | |
| *buf++ = 0xf7; | |
| *buf = 0xc0 | reg_map[SLJIT_TEMPORARY_REG2]; | |
| #endif | |
| #endif | |
| switch (op) { | |
| case SLJIT_UMUL: | |
| *buf |= 4 << 3; | |
| break; | |
| case SLJIT_SMUL: | |
| *buf |= 5 << 3; | |
| break; | |
| case SLJIT_UDIV: | |
| *buf |= 6 << 3; | |
| break; | |
| case SLJIT_SDIV: | |
| *buf |= 7 << 3; | |
| break; | |
| } | |
| #if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) && !defined(_WIN64) | |
| EMIT_MOV(compiler, SLJIT_TEMPORARY_REG2, 0, TMP_REGISTER, 0); | |
| #endif | |
| break; | |
| } | |
| return SLJIT_SUCCESS; | |
| } | |
| #define ENCODE_PREFIX(prefix) \ | #define ENCODE_PREFIX(prefix) \ |
| do { \ | do { \ |
| code = (sljit_ub*)ensure_buf(compiler, 1 + 1); \ | code = (sljit_ub*)ensure_buf(compiler, 1 + 1); \ |
| Line 853 static int emit_clz(struct sljit_compiler *compiler, i | Line 959 static int emit_clz(struct sljit_compiler *compiler, i |
| sljit_ub* code; | sljit_ub* code; |
| int dst_r; | int dst_r; |
| SLJIT_UNUSED_ARG(op); | |
| if (SLJIT_UNLIKELY(dst == SLJIT_UNUSED)) { | if (SLJIT_UNLIKELY(dst == SLJIT_UNUSED)) { |
| /* Just set the zero flag. */ | /* Just set the zero flag. */ |
| EMIT_MOV(compiler, TMP_REGISTER, 0, src, srcw); | EMIT_MOV(compiler, TMP_REGISTER, 0, src, srcw); |
| Line 1718 static int emit_shift(struct sljit_compiler *compiler, | Line 1825 static int emit_shift(struct sljit_compiler *compiler, |
| EMIT_MOV(compiler, SLJIT_PREF_SHIFT_REG, 0, TMP_REGISTER, 0); | EMIT_MOV(compiler, SLJIT_PREF_SHIFT_REG, 0, TMP_REGISTER, 0); |
| } | } |
| else { | else { |
| /* This case is really difficult, since ecx can be used for | /* This case is really difficult, since ecx itself may used for |
| addressing as well, and we must ensure to work even in that case. */ | addressing, and we must ensure to work even in that case. */ |
| EMIT_MOV(compiler, TMP_REGISTER, 0, src1, src1w); | |
| #if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) | #if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) |
| EMIT_MOV(compiler, TMP_REG2, 0, SLJIT_PREF_SHIFT_REG, 0); | EMIT_MOV(compiler, TMP_REG2, 0, SLJIT_PREF_SHIFT_REG, 0); |
| #else | #else |
| /* [esp - 4] is reserved for eflags. */ | /* [esp - 4] is reserved for eflags. */ |
| EMIT_MOV(compiler, SLJIT_MEM1(SLJIT_LOCALS_REG), -(int)(2 * sizeof(sljit_w)), SLJIT_PREF_SHIFT_REG, 0); | EMIT_MOV(compiler, SLJIT_MEM1(SLJIT_LOCALS_REG), -(int)(2 * sizeof(sljit_w)), SLJIT_PREF_SHIFT_REG, 0); |
| #endif | #endif |
| EMIT_MOV(compiler, TMP_REGISTER, 0, src1, src1w); | |
| EMIT_MOV(compiler, SLJIT_PREF_SHIFT_REG, 0, src2, src2w); | EMIT_MOV(compiler, SLJIT_PREF_SHIFT_REG, 0, src2, src2w); |
| code = emit_x86_instruction(compiler, 1 | EX86_SHIFT_INS, SLJIT_PREF_SHIFT_REG, 0, TMP_REGISTER, 0); | code = emit_x86_instruction(compiler, 1 | EX86_SHIFT_INS, SLJIT_PREF_SHIFT_REG, 0, TMP_REGISTER, 0); |
| FAIL_IF(!code); | FAIL_IF(!code); |
| *code |= mode; | *code |= mode; |
| #if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) | #if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) |
| EMIT_MOV(compiler, SLJIT_PREF_SHIFT_REG, 0, TMP_REG2, 0); | EMIT_MOV(compiler, SLJIT_PREF_SHIFT_REG, 0, TMP_REG2, 0); |
| #else | #else |
| Line 1745 static int emit_shift(struct sljit_compiler *compiler, | Line 1850 static int emit_shift(struct sljit_compiler *compiler, |
| return SLJIT_SUCCESS; | return SLJIT_SUCCESS; |
| } | } |
| static int emit_shift_with_flags(struct sljit_compiler *compiler, | |
| sljit_ub mode, int set_flags, | |
| int dst, sljit_w dstw, | |
| int src1, sljit_w src1w, | |
| int src2, sljit_w src2w) | |
| { | |
| /* The CPU does not set flags if the shift count is 0. */ | |
| if (src2 & SLJIT_IMM) { | |
| #if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) | |
| if ((src2w & 0x3f) != 0 || (compiler->mode32 && (src2w & 0x1f) != 0)) | |
| return emit_shift(compiler, mode, dst, dstw, src1, src1w, src2, src2w); | |
| #else | |
| if ((src2w & 0x1f) != 0) | |
| return emit_shift(compiler, mode, dst, dstw, src1, src1w, src2, src2w); | |
| #endif | |
| if (!set_flags) | |
| return emit_mov(compiler, dst, dstw, src1, src1w); | |
| /* OR dst, src, 0 */ | |
| return emit_cum_binary(compiler, 0x0b, 0x09, 0x1 << 3, 0x0d, | |
| dst, dstw, src1, src1w, SLJIT_IMM, 0); | |
| } | |
| if (!set_flags) | |
| return emit_shift(compiler, mode, dst, dstw, src1, src1w, src2, src2w); | |
| if (!(dst >= SLJIT_TEMPORARY_REG1 && dst <= SLJIT_NO_REGISTERS)) | |
| FAIL_IF(emit_cmp_binary(compiler, src1, src1w, SLJIT_IMM, 0)); | |
| FAIL_IF(emit_shift(compiler,mode, dst, dstw, src1, src1w, src2, src2w)); | |
| if (dst >= SLJIT_TEMPORARY_REG1 && dst <= SLJIT_NO_REGISTERS) | |
| return emit_cmp_binary(compiler, dst, dstw, SLJIT_IMM, 0); | |
| return SLJIT_SUCCESS; | |
| } | |
| SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_op2(struct sljit_compiler *compiler, int op, | SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_op2(struct sljit_compiler *compiler, int op, |
| int dst, sljit_w dstw, | int dst, sljit_w dstw, |
| int src1, sljit_w src1w, | int src1, sljit_w src1w, |
| Line 1824 SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_op2(struct slj | Line 1964 SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_op2(struct slj |
| return emit_cum_binary(compiler, 0x33, 0x31, 0x6 << 3, 0x35, | return emit_cum_binary(compiler, 0x33, 0x31, 0x6 << 3, 0x35, |
| dst, dstw, src1, src1w, src2, src2w); | dst, dstw, src1, src1w, src2, src2w); |
| case SLJIT_SHL: | case SLJIT_SHL: |
| return emit_shift(compiler, 0x4 << 3, | return emit_shift_with_flags(compiler, 0x4 << 3, GET_FLAGS(op), |
| dst, dstw, src1, src1w, src2, src2w); | dst, dstw, src1, src1w, src2, src2w); |
| case SLJIT_LSHR: | case SLJIT_LSHR: |
| return emit_shift(compiler, 0x5 << 3, | return emit_shift_with_flags(compiler, 0x5 << 3, GET_FLAGS(op), |
| dst, dstw, src1, src1w, src2, src2w); | dst, dstw, src1, src1w, src2, src2w); |
| case SLJIT_ASHR: | case SLJIT_ASHR: |
| return emit_shift(compiler, 0x7 << 3, | return emit_shift_with_flags(compiler, 0x7 << 3, GET_FLAGS(op), |
| dst, dstw, src1, src1w, src2, src2w); | dst, dstw, src1, src1w, src2, src2w); |
| } | } |
| return SLJIT_SUCCESS; | return SLJIT_SUCCESS; |
| } | } |
| SLJIT_API_FUNC_ATTRIBUTE int sljit_get_register_index(int reg) | |
| { | |
| check_sljit_get_register_index(reg); | |
| #if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) | |
| if (reg == SLJIT_TEMPORARY_EREG1 || reg == SLJIT_TEMPORARY_EREG2 | |
| || reg == SLJIT_SAVED_EREG1 || reg == SLJIT_SAVED_EREG2) | |
| return -1; | |
| #endif | |
| return reg_map[reg]; | |
| } | |
| SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_op_custom(struct sljit_compiler *compiler, | |
| void *instruction, int size) | |
| { | |
| sljit_ub *buf; | |
| CHECK_ERROR(); | |
| check_sljit_emit_op_custom(compiler, instruction, size); | |
| SLJIT_ASSERT(size > 0 && size < 16); | |
| buf = (sljit_ub*)ensure_buf(compiler, 1 + size); | |
| FAIL_IF(!buf); | |
| INC_SIZE(size); | |
| SLJIT_MEMMOVE(buf, instruction, size); | |
| return SLJIT_SUCCESS; | |
| } | |
| /* --------------------------------------------------------------------- */ | /* --------------------------------------------------------------------- */ |
| /* Floating point operators */ | /* Floating point operators */ |
| /* --------------------------------------------------------------------- */ | /* --------------------------------------------------------------------- */ |
| Line 2582 SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_cond_value(str | Line 2749 SLJIT_API_FUNC_ATTRIBUTE int sljit_emit_cond_value(str |
| *buf++ = 0x0f; | *buf++ = 0x0f; |
| *buf++ = 0xb6; | *buf++ = 0xb6; |
| if (dst >= SLJIT_GENERAL_REG1 && dst <= SLJIT_NO_REGISTERS) | if (dst >= SLJIT_SAVED_REG1 && dst <= SLJIT_NO_REGISTERS) |
| *buf = 0xC0 | (reg_map[dst] << 3); | *buf = 0xC0 | (reg_map[dst] << 3); |
| else { | else { |
| *buf = 0xC0; | *buf = 0xC0; |