diff options
Diffstat (limited to 'thirdparty/pcre2/src/sljit/sljitNativeX86_common.c')
-rw-r--r-- | thirdparty/pcre2/src/sljit/sljitNativeX86_common.c | 537 |
1 files changed, 419 insertions, 118 deletions
diff --git a/thirdparty/pcre2/src/sljit/sljitNativeX86_common.c b/thirdparty/pcre2/src/sljit/sljitNativeX86_common.c index c7dd9be8fd..651942be80 100644 --- a/thirdparty/pcre2/src/sljit/sljitNativeX86_common.c +++ b/thirdparty/pcre2/src/sljit/sljitNativeX86_common.c @@ -26,11 +26,7 @@ SLJIT_API_FUNC_ATTRIBUTE const char* sljit_get_platform_name(void) { -#if (defined SLJIT_X86_32_FASTCALL && SLJIT_X86_32_FASTCALL) - return "x86" SLJIT_CPUINFO " ABI:fastcall"; -#else return "x86" SLJIT_CPUINFO; -#endif } /* @@ -78,10 +74,7 @@ static const sljit_u8 reg_map[SLJIT_NUMBER_OF_REGISTERS + 3] = { #define CHECK_EXTRA_REGS(p, w, do) \ if (p >= SLJIT_R3 && p <= SLJIT_S3) { \ - if (p <= compiler->scratches) \ - w = compiler->scratches_offset + ((p) - SLJIT_R3) * SSIZE_OF(sw); \ - else \ - w = compiler->locals_offset + ((p) - SLJIT_S2) * SSIZE_OF(sw); \ + w = (2 * SSIZE_OF(sw)) + ((p) - SLJIT_R3) * SSIZE_OF(sw); \ p = SLJIT_MEM1(SLJIT_SP); \ do; \ } @@ -181,6 +174,7 @@ static const sljit_u8 freg_lmap[SLJIT_NUMBER_OF_FLOAT_REGISTERS + 1] = { #define AND_rm_r 0x21 #define ANDPD_x_xm 0x54 #define BSR_r_rm (/* GROUP_0F */ 0xbd) +#define BSF_r_rm (/* GROUP_0F */ 0xbc) #define CALL_i32 0xe8 #define CALL_rm (/* GROUP_FF */ 2 << 3) #define CDQ 0x99 @@ -194,6 +188,8 @@ static const sljit_u8 freg_lmap[SLJIT_NUMBER_OF_FLOAT_REGISTERS + 1] = { #define CVTTSD2SI_r_xm 0x2c #define DIV (/* GROUP_F7 */ 6 << 3) #define DIVSD_x_xm 0x5e +#define FLDS 0xd9 +#define FLDL 0xdd #define FSTPS 0xd9 #define FSTPD 0xdd #define INT3 0xcc @@ -209,6 +205,7 @@ static const sljit_u8 freg_lmap[SLJIT_NUMBER_OF_FLOAT_REGISTERS + 1] = { #define JMP_rm (/* GROUP_FF */ 4 << 3) #define LEA_r_m 0x8d #define LOOP_i8 0xe2 +#define LZCNT_r_rm (/* GROUP_F3 */ /* GROUP_0F */ 0xbd) #define MOV_r_rm 0x8b #define MOV_r_i32 0xb8 #define MOV_rm_r 0x89 @@ -242,6 +239,8 @@ static const sljit_u8 freg_lmap[SLJIT_NUMBER_OF_FLOAT_REGISTERS + 1] = { #define PUSH_r 0x50 #define PUSH_rm (/* GROUP_FF */ 6 << 3) #define PUSHF 0x9c +#define ROL (/* SHIFT */ 0 << 3) +#define ROR (/* SHIFT */ 1 << 3) #define RET_near 0xc3 #define RET_i16 0xc2 #define SBB (/* BINARY */ 3 << 3) @@ -250,6 +249,8 @@ static const sljit_u8 freg_lmap[SLJIT_NUMBER_OF_FLOAT_REGISTERS + 1] = { #define SBB_rm_r 0x19 #define SAR (/* SHIFT */ 7 << 3) #define SHL (/* SHIFT */ 4 << 3) +#define SHLD (/* GROUP_0F */ 0xa5) +#define SHRD (/* GROUP_0F */ 0xad) #define SHR (/* SHIFT */ 5 << 3) #define SUB (/* BINARY */ 5 << 3) #define SUB_EAX_i32 0x2d @@ -258,6 +259,7 @@ static const sljit_u8 freg_lmap[SLJIT_NUMBER_OF_FLOAT_REGISTERS + 1] = { #define SUBSD_x_xm 0x5c #define TEST_EAX_i32 0xa9 #define TEST_rm_r 0x85 +#define TZCNT_r_rm (/* GROUP_F3 */ /* GROUP_0F */ 0xbc) #define UCOMISD_x_xm 0x2e #define UNPCKLPD_x_xm 0x14 #define XCHG_EAX_r 0x90 @@ -269,6 +271,7 @@ static const sljit_u8 freg_lmap[SLJIT_NUMBER_OF_FLOAT_REGISTERS + 1] = { #define XORPD_x_xm 0x57 #define GROUP_0F 0x0f +#define GROUP_F3 0xf3 #define GROUP_F7 0xf7 #define GROUP_FF 0xff #define GROUP_BINARY_81 0x81 @@ -290,10 +293,15 @@ static const sljit_u8 freg_lmap[SLJIT_NUMBER_OF_FLOAT_REGISTERS + 1] = { /* Multithreading does not affect these static variables, since they store built-in CPU features. Therefore they can be overwritten by different threads if they detect the CPU features in the same time. */ +#define CPU_FEATURE_DETECTED 0x001 #if (defined SLJIT_DETECT_SSE2 && SLJIT_DETECT_SSE2) -static sljit_s32 cpu_has_sse2 = -1; +#define CPU_FEATURE_SSE2 0x002 #endif -static sljit_s32 cpu_has_cmov = -1; +#define CPU_FEATURE_LZCNT 0x004 +#define CPU_FEATURE_TZCNT 0x008 +#define CPU_FEATURE_CMOV 0x010 + +static sljit_u32 cpu_feature_list = 0; #ifdef _WIN32_WCE #include <cmnintrin.h> @@ -326,18 +334,65 @@ static SLJIT_INLINE void sljit_unaligned_store_sw(void *addr, sljit_sw value) static void get_cpu_features(void) { - sljit_u32 features; + sljit_u32 feature_list = CPU_FEATURE_DETECTED; + sljit_u32 value; #if defined(_MSC_VER) && _MSC_VER >= 1400 int CPUInfo[4]; + + __cpuid(CPUInfo, 0); + if (CPUInfo[0] >= 7) { + __cpuidex(CPUInfo, 7, 0); + if (CPUInfo[1] & 0x8) + feature_list |= CPU_FEATURE_TZCNT; + } + + __cpuid(CPUInfo, (int)0x80000001); + if (CPUInfo[2] & 0x20) + feature_list |= CPU_FEATURE_LZCNT; + __cpuid(CPUInfo, 1); - features = (sljit_u32)CPUInfo[3]; + value = (sljit_u32)CPUInfo[3]; #elif defined(__GNUC__) || defined(__INTEL_COMPILER) || defined(__SUNPRO_C) /* AT&T syntax. */ __asm__ ( + "movl $0x0, %%eax\n" + "lzcnt %%eax, %%eax\n" + "setnz %%al\n" + "movl %%eax, %0\n" + : "=g" (value) + : +#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) + : "eax" +#else + : "rax" +#endif + ); + + if (value & 0x1) + feature_list |= CPU_FEATURE_LZCNT; + + __asm__ ( + "movl $0x0, %%eax\n" + "tzcnt %%eax, %%eax\n" + "setnz %%al\n" + "movl %%eax, %0\n" + : "=g" (value) + : +#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) + : "eax" +#else + : "rax" +#endif + ); + + if (value & 0x1) + feature_list |= CPU_FEATURE_TZCNT; + + __asm__ ( "movl $0x1, %%eax\n" #if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) /* On x86-32, there is no red zone, so this @@ -349,7 +404,7 @@ static void get_cpu_features(void) "pop %%ebx\n" #endif "movl %%edx, %0\n" - : "=g" (features) + : "=g" (value) : #if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) : "%eax", "%ecx", "%edx" @@ -362,46 +417,82 @@ static void get_cpu_features(void) /* Intel syntax. */ __asm { + mov eax, 0 + lzcnt eax, eax + setnz al + mov value, eax + } + + if (value & 0x1) + feature_list |= CPU_FEATURE_LZCNT; + + __asm { + mov eax, 0 + tzcnt eax, eax + setnz al + mov value, eax + } + + if (value & 0x1) + feature_list |= CPU_FEATURE_TZCNT; + + __asm { mov eax, 1 cpuid - mov features, edx + mov value, edx } #endif /* _MSC_VER && _MSC_VER >= 1400 */ #if (defined SLJIT_DETECT_SSE2 && SLJIT_DETECT_SSE2) - cpu_has_sse2 = (features >> 26) & 0x1; + if (value & 0x4000000) + feature_list |= CPU_FEATURE_SSE2; #endif - cpu_has_cmov = (features >> 15) & 0x1; + if (value & 0x8000) + feature_list |= CPU_FEATURE_CMOV; + + cpu_feature_list = feature_list; } static sljit_u8 get_jump_code(sljit_uw type) { switch (type) { case SLJIT_EQUAL: - case SLJIT_EQUAL_F64: + case SLJIT_F_EQUAL: + case SLJIT_UNORDERED_OR_EQUAL: + case SLJIT_ORDERED_EQUAL: /* Not supported. */ return 0x84 /* je */; case SLJIT_NOT_EQUAL: - case SLJIT_NOT_EQUAL_F64: + case SLJIT_F_NOT_EQUAL: + case SLJIT_ORDERED_NOT_EQUAL: + case SLJIT_UNORDERED_OR_NOT_EQUAL: /* Not supported. */ return 0x85 /* jne */; case SLJIT_LESS: case SLJIT_CARRY: - case SLJIT_LESS_F64: + case SLJIT_F_LESS: + case SLJIT_UNORDERED_OR_LESS: + case SLJIT_UNORDERED_OR_GREATER: return 0x82 /* jc */; case SLJIT_GREATER_EQUAL: case SLJIT_NOT_CARRY: - case SLJIT_GREATER_EQUAL_F64: + case SLJIT_F_GREATER_EQUAL: + case SLJIT_ORDERED_GREATER_EQUAL: + case SLJIT_ORDERED_LESS_EQUAL: return 0x83 /* jae */; case SLJIT_GREATER: - case SLJIT_GREATER_F64: + case SLJIT_F_GREATER: + case SLJIT_ORDERED_LESS: + case SLJIT_ORDERED_GREATER: return 0x87 /* jnbe */; case SLJIT_LESS_EQUAL: - case SLJIT_LESS_EQUAL_F64: + case SLJIT_F_LESS_EQUAL: + case SLJIT_UNORDERED_OR_GREATER_EQUAL: + case SLJIT_UNORDERED_OR_LESS_EQUAL: return 0x86 /* jbe */; case SLJIT_SIG_LESS: @@ -422,10 +513,10 @@ static sljit_u8 get_jump_code(sljit_uw type) case SLJIT_NOT_OVERFLOW: return 0x81 /* jno */; - case SLJIT_UNORDERED_F64: + case SLJIT_UNORDERED: return 0x8a /* jp */; - case SLJIT_ORDERED_F64: + case SLJIT_ORDERED: return 0x8b /* jpo */; } return 0; @@ -449,13 +540,13 @@ static sljit_u8* generate_near_jump_code(struct sljit_jump *jump, sljit_u8 *code else label_addr = jump->u.target - (sljit_uw)executable_offset; - short_jump = (sljit_sw)(label_addr - (jump->addr + 2)) >= -128 && (sljit_sw)(label_addr - (jump->addr + 2)) <= 127; - #if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) if ((sljit_sw)(label_addr - (jump->addr + 1)) > HALFWORD_MAX || (sljit_sw)(label_addr - (jump->addr + 1)) < HALFWORD_MIN) return generate_far_jump_code(jump, code_ptr); #endif + short_jump = (sljit_sw)(label_addr - (jump->addr + 2)) >= -128 && (sljit_sw)(label_addr - (jump->addr + 2)) <= 127; + if (type == SLJIT_JUMP) { if (short_jump) *code_ptr++ = JMP_i8; @@ -581,32 +672,33 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil jump = compiler->jumps; while (jump) { - jump_addr = jump->addr + (sljit_uw)executable_offset; + if (jump->flags & (PATCH_MB | PATCH_MW)) { + if (jump->flags & JUMP_LABEL) + jump_addr = jump->u.label->addr; + else + jump_addr = jump->u.target; - if (jump->flags & PATCH_MB) { - SLJIT_ASSERT((sljit_sw)(jump->u.label->addr - (jump_addr + sizeof(sljit_s8))) >= -128 && (sljit_sw)(jump->u.label->addr - (jump_addr + sizeof(sljit_s8))) <= 127); - *(sljit_u8*)jump->addr = U8(jump->u.label->addr - (jump_addr + sizeof(sljit_s8))); - } else if (jump->flags & PATCH_MW) { - if (jump->flags & JUMP_LABEL) { -#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) - sljit_unaligned_store_sw((void*)jump->addr, (sljit_sw)(jump->u.label->addr - (jump_addr + sizeof(sljit_sw)))); -#else - SLJIT_ASSERT((sljit_sw)(jump->u.label->addr - (jump_addr + sizeof(sljit_s32))) >= HALFWORD_MIN && (sljit_sw)(jump->u.label->addr - (jump_addr + sizeof(sljit_s32))) <= HALFWORD_MAX); - sljit_unaligned_store_s32((void*)jump->addr, (sljit_s32)(jump->u.label->addr - (jump_addr + sizeof(sljit_s32)))); -#endif - } - else { + jump_addr -= jump->addr + (sljit_uw)executable_offset; + + if (jump->flags & PATCH_MB) { + jump_addr -= sizeof(sljit_s8); + SLJIT_ASSERT((sljit_sw)jump_addr >= -128 && (sljit_sw)jump_addr <= 127); + *(sljit_u8*)jump->addr = U8(jump_addr); + } else { + jump_addr -= sizeof(sljit_s32); #if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) - sljit_unaligned_store_sw((void*)jump->addr, (sljit_sw)(jump->u.target - (jump_addr + sizeof(sljit_sw)))); + sljit_unaligned_store_sw((void*)jump->addr, (sljit_sw)jump_addr); #else - SLJIT_ASSERT((sljit_sw)(jump->u.target - (jump_addr + sizeof(sljit_s32))) >= HALFWORD_MIN && (sljit_sw)(jump->u.target - (jump_addr + sizeof(sljit_s32))) <= HALFWORD_MAX); - sljit_unaligned_store_s32((void*)jump->addr, (sljit_s32)(jump->u.target - (jump_addr + sizeof(sljit_s32)))); + SLJIT_ASSERT((sljit_sw)jump_addr >= HALFWORD_MIN && (sljit_sw)jump_addr <= HALFWORD_MAX); + sljit_unaligned_store_s32((void*)jump->addr, (sljit_s32)jump_addr); #endif } } #if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) - else if (jump->flags & PATCH_MD) - sljit_unaligned_store_sw((void*)jump->addr, (sljit_sw)jump->u.label->addr); + else if (jump->flags & PATCH_MD) { + SLJIT_ASSERT(jump->flags & JUMP_LABEL); + sljit_unaligned_store_sw((void*)jump->addr, (sljit_sw)jump->u.label->addr); + } #endif jump = jump->next; @@ -647,9 +739,9 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_has_cpu_feature(sljit_s32 feature_type) #ifdef SLJIT_IS_FPU_AVAILABLE return SLJIT_IS_FPU_AVAILABLE; #elif (defined SLJIT_DETECT_SSE2 && SLJIT_DETECT_SSE2) - if (cpu_has_sse2 == -1) + if (cpu_feature_list == 0) get_cpu_features(); - return cpu_has_sse2; + return (cpu_feature_list & CPU_FEATURE_SSE2) != 0; #else /* SLJIT_DETECT_SSE2 */ return 1; #endif /* SLJIT_DETECT_SSE2 */ @@ -657,31 +749,57 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_has_cpu_feature(sljit_s32 feature_type) #if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) case SLJIT_HAS_VIRTUAL_REGISTERS: return 1; -#endif +#endif /* SLJIT_CONFIG_X86_32 */ case SLJIT_HAS_CLZ: + if (cpu_feature_list == 0) + get_cpu_features(); + + return (cpu_feature_list & CPU_FEATURE_LZCNT) ? 1 : 2; + + case SLJIT_HAS_CTZ: + if (cpu_feature_list == 0) + get_cpu_features(); + + return (cpu_feature_list & CPU_FEATURE_TZCNT) ? 1 : 2; + case SLJIT_HAS_CMOV: - if (cpu_has_cmov == -1) + if (cpu_feature_list == 0) get_cpu_features(); - return cpu_has_cmov; + return (cpu_feature_list & CPU_FEATURE_CMOV) != 0; + case SLJIT_HAS_ROT: case SLJIT_HAS_PREFETCH: return 1; case SLJIT_HAS_SSE2: #if (defined SLJIT_DETECT_SSE2 && SLJIT_DETECT_SSE2) - if (cpu_has_sse2 == -1) + if (cpu_feature_list == 0) get_cpu_features(); - return cpu_has_sse2; -#else + return (cpu_feature_list & CPU_FEATURE_SSE2) != 0; +#else /* !SLJIT_DETECT_SSE2 */ return 1; -#endif +#endif /* SLJIT_DETECT_SSE2 */ default: return 0; } } +SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_cmp_info(sljit_s32 type) +{ + if (type < SLJIT_UNORDERED || type > SLJIT_ORDERED_LESS_EQUAL) + return 0; + + switch (type) { + case SLJIT_ORDERED_EQUAL: + case SLJIT_UNORDERED_OR_NOT_EQUAL: + return 0; + } + + return 1; +} + /* --------------------------------------------------------------------- */ /* Operators */ /* --------------------------------------------------------------------- */ @@ -1385,47 +1503,75 @@ static sljit_s32 emit_not_with_flags(struct sljit_compiler *compiler, #if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) static const sljit_sw emit_clz_arg = 32 + 31; +static const sljit_sw emit_ctz_arg = 32; #endif -static sljit_s32 emit_clz(struct sljit_compiler *compiler, sljit_s32 op_flags, +static sljit_s32 emit_clz_ctz(struct sljit_compiler *compiler, sljit_s32 is_clz, sljit_s32 dst, sljit_sw dstw, sljit_s32 src, sljit_sw srcw) { sljit_u8* inst; sljit_s32 dst_r; + sljit_sw max; - SLJIT_UNUSED_ARG(op_flags); - - if (cpu_has_cmov == -1) + if (cpu_feature_list == 0) get_cpu_features(); dst_r = FAST_IS_REG(dst) ? dst : TMP_REG1; + if (is_clz ? (cpu_feature_list & CPU_FEATURE_LZCNT) : (cpu_feature_list & CPU_FEATURE_TZCNT)) { + /* Group prefix added separately. */ + inst = (sljit_u8*)ensure_buf(compiler, 1 + 1); + FAIL_IF(!inst); + INC_SIZE(1); + *inst++ = GROUP_F3; + + inst = emit_x86_instruction(compiler, 2, dst_r, 0, src, srcw); + FAIL_IF(!inst); + *inst++ = GROUP_0F; + *inst = is_clz ? LZCNT_r_rm : TZCNT_r_rm; + + if (dst & SLJIT_MEM) + EMIT_MOV(compiler, dst, dstw, TMP_REG1, 0); + return SLJIT_SUCCESS; + } + inst = emit_x86_instruction(compiler, 2, dst_r, 0, src, srcw); FAIL_IF(!inst); *inst++ = GROUP_0F; - *inst = BSR_r_rm; + *inst = is_clz ? BSR_r_rm : BSF_r_rm; #if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) - if (cpu_has_cmov) { + max = is_clz ? (32 + 31) : 32; + + if (cpu_feature_list & CPU_FEATURE_CMOV) { if (dst_r != TMP_REG1) { - EMIT_MOV(compiler, TMP_REG1, 0, SLJIT_IMM, 32 + 31); + EMIT_MOV(compiler, TMP_REG1, 0, SLJIT_IMM, max); inst = emit_x86_instruction(compiler, 2, dst_r, 0, TMP_REG1, 0); } else - inst = emit_x86_instruction(compiler, 2, dst_r, 0, SLJIT_MEM0(), (sljit_sw)&emit_clz_arg); + inst = emit_x86_instruction(compiler, 2, dst_r, 0, SLJIT_MEM0(), is_clz ? (sljit_sw)&emit_clz_arg : (sljit_sw)&emit_ctz_arg); FAIL_IF(!inst); *inst++ = GROUP_0F; *inst = CMOVE_r_rm; } else - FAIL_IF(sljit_emit_cmov_generic(compiler, SLJIT_EQUAL, dst_r, SLJIT_IMM, 32 + 31)); + FAIL_IF(sljit_emit_cmov_generic(compiler, SLJIT_EQUAL, dst_r, SLJIT_IMM, max)); - inst = emit_x86_instruction(compiler, 1 | EX86_BIN_INS, SLJIT_IMM, 31, dst_r, 0); + if (is_clz) { + inst = emit_x86_instruction(compiler, 1 | EX86_BIN_INS, SLJIT_IMM, 31, dst_r, 0); + FAIL_IF(!inst); + *(inst + 1) |= XOR; + } #else - if (cpu_has_cmov) { - EMIT_MOV(compiler, TMP_REG2, 0, SLJIT_IMM, !(op_flags & SLJIT_32) ? (64 + 63) : (32 + 31)); + if (is_clz) + max = compiler->mode32 ? (32 + 31) : (64 + 63); + else + max = compiler->mode32 ? 32 : 64; + + if (cpu_feature_list & CPU_FEATURE_CMOV) { + EMIT_MOV(compiler, TMP_REG2, 0, SLJIT_IMM, max); inst = emit_x86_instruction(compiler, 2, dst_r, 0, TMP_REG2, 0); FAIL_IF(!inst); @@ -1433,14 +1579,15 @@ static sljit_s32 emit_clz(struct sljit_compiler *compiler, sljit_s32 op_flags, *inst = CMOVE_r_rm; } else - FAIL_IF(sljit_emit_cmov_generic(compiler, SLJIT_EQUAL, dst_r, SLJIT_IMM, !(op_flags & SLJIT_32) ? (64 + 63) : (32 + 31))); + FAIL_IF(sljit_emit_cmov_generic(compiler, SLJIT_EQUAL, dst_r, SLJIT_IMM, max)); - inst = emit_x86_instruction(compiler, 1 | EX86_BIN_INS, SLJIT_IMM, !(op_flags & SLJIT_32) ? 63 : 31, dst_r, 0); + if (is_clz) { + inst = emit_x86_instruction(compiler, 1 | EX86_BIN_INS, SLJIT_IMM, max >> 1, dst_r, 0); + FAIL_IF(!inst); + *(inst + 1) |= XOR; + } #endif - FAIL_IF(!inst); - *(inst + 1) |= XOR; - if (dst & SLJIT_MEM) EMIT_MOV(compiler, dst, dstw, TMP_REG1, 0); return SLJIT_SUCCESS; @@ -1578,7 +1725,8 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op1(struct sljit_compiler *compile return emit_unary(compiler, NOT_rm, dst, dstw, src, srcw); case SLJIT_CLZ: - return emit_clz(compiler, op_flags, dst, dstw, src, srcw); + case SLJIT_CTZ: + return emit_clz_ctz(compiler, (op == SLJIT_CLZ), dst, dstw, src, srcw); } return SLJIT_SUCCESS; @@ -2116,6 +2264,9 @@ static sljit_s32 emit_shift(struct sljit_compiler *compiler, sljit_s32 src1, sljit_sw src1w, sljit_s32 src2, sljit_sw src2w) { +#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) + sljit_s32 mode32; +#endif sljit_u8* inst; if ((src2 & SLJIT_IMM) || (src2 == SLJIT_PREF_SHIFT_REG)) { @@ -2155,40 +2306,61 @@ static sljit_s32 emit_shift(struct sljit_compiler *compiler, inst = emit_x86_instruction(compiler, 1 | EX86_SHIFT_INS, SLJIT_PREF_SHIFT_REG, 0, TMP_REG1, 0); FAIL_IF(!inst); *inst |= mode; - EMIT_MOV(compiler, SLJIT_PREF_SHIFT_REG, 0, TMP_REG1, 0); + return emit_mov(compiler, SLJIT_PREF_SHIFT_REG, 0, TMP_REG1, 0); } - else if (FAST_IS_REG(dst) && dst != src2 && dst != TMP_REG1 && !ADDRESSING_DEPENDS_ON(src2, dst)) { + + if (FAST_IS_REG(dst) && dst != src2 && dst != TMP_REG1 && !ADDRESSING_DEPENDS_ON(src2, dst)) { if (src1 != dst) EMIT_MOV(compiler, dst, 0, src1, src1w); +#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) + mode32 = compiler->mode32; + compiler->mode32 = 0; +#endif EMIT_MOV(compiler, TMP_REG1, 0, SLJIT_PREF_SHIFT_REG, 0); +#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) + compiler->mode32 = mode32; +#endif EMIT_MOV(compiler, SLJIT_PREF_SHIFT_REG, 0, src2, src2w); inst = emit_x86_instruction(compiler, 1 | EX86_SHIFT_INS, SLJIT_PREF_SHIFT_REG, 0, dst, 0); FAIL_IF(!inst); *inst |= mode; +#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) + compiler->mode32 = 0; +#endif EMIT_MOV(compiler, SLJIT_PREF_SHIFT_REG, 0, TMP_REG1, 0); +#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) + compiler->mode32 = mode32; +#endif + return SLJIT_SUCCESS; } - else { - /* This case is complex since ecx itself may be used for - addressing, and this case must be supported as well. */ - EMIT_MOV(compiler, TMP_REG1, 0, src1, src1w); + + /* This case is complex since ecx itself may be used for + addressing, and this case must be supported as well. */ + EMIT_MOV(compiler, TMP_REG1, 0, src1, src1w); #if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) - EMIT_MOV(compiler, SLJIT_MEM1(SLJIT_SP), 0, SLJIT_PREF_SHIFT_REG, 0); - EMIT_MOV(compiler, SLJIT_PREF_SHIFT_REG, 0, src2, src2w); - inst = emit_x86_instruction(compiler, 1 | EX86_SHIFT_INS, SLJIT_PREF_SHIFT_REG, 0, TMP_REG1, 0); - FAIL_IF(!inst); - *inst |= mode; - EMIT_MOV(compiler, SLJIT_PREF_SHIFT_REG, 0, SLJIT_MEM1(SLJIT_SP), 0); + EMIT_MOV(compiler, SLJIT_MEM1(SLJIT_SP), 0, SLJIT_PREF_SHIFT_REG, 0); +#else /* !SLJIT_CONFIG_X86_32 */ + mode32 = compiler->mode32; + compiler->mode32 = 0; + EMIT_MOV(compiler, TMP_REG2, 0, SLJIT_PREF_SHIFT_REG, 0); + compiler->mode32 = mode32; +#endif /* SLJIT_CONFIG_X86_32 */ + + EMIT_MOV(compiler, SLJIT_PREF_SHIFT_REG, 0, src2, src2w); + inst = emit_x86_instruction(compiler, 1 | EX86_SHIFT_INS, SLJIT_PREF_SHIFT_REG, 0, TMP_REG1, 0); + FAIL_IF(!inst); + *inst |= mode; + +#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) + EMIT_MOV(compiler, SLJIT_PREF_SHIFT_REG, 0, SLJIT_MEM1(SLJIT_SP), 0); #else - EMIT_MOV(compiler, TMP_REG2, 0, SLJIT_PREF_SHIFT_REG, 0); - EMIT_MOV(compiler, SLJIT_PREF_SHIFT_REG, 0, src2, src2w); - inst = emit_x86_instruction(compiler, 1 | EX86_SHIFT_INS, SLJIT_PREF_SHIFT_REG, 0, TMP_REG1, 0); - FAIL_IF(!inst); - *inst |= mode; - EMIT_MOV(compiler, SLJIT_PREF_SHIFT_REG, 0, TMP_REG2, 0); -#endif - if (dst != TMP_REG1) - return emit_mov(compiler, dst, dstw, TMP_REG1, 0); - } + compiler->mode32 = 0; + EMIT_MOV(compiler, SLJIT_PREF_SHIFT_REG, 0, TMP_REG2, 0); + compiler->mode32 = mode32; +#endif /* SLJIT_CONFIG_X86_32 */ + + if (dst != TMP_REG1) + return emit_mov(compiler, dst, dstw, TMP_REG1, 0); return SLJIT_SUCCESS; } @@ -2202,12 +2374,13 @@ static sljit_s32 emit_shift_with_flags(struct sljit_compiler *compiler, /* 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) + src2w &= compiler->mode32 ? 0x1f : 0x3f; +#else /* !SLJIT_CONFIG_X86_64 */ + src2w &= 0x1f; +#endif /* SLJIT_CONFIG_X86_64 */ + if (src2w != 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 */ @@ -2289,14 +2462,23 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2(struct sljit_compiler *compile return emit_cum_binary(compiler, BINARY_OPCODE(XOR), dst, dstw, src1, src1w, src2, src2w); case SLJIT_SHL: + case SLJIT_MSHL: return emit_shift_with_flags(compiler, SHL, HAS_FLAGS(op), dst, dstw, src1, src1w, src2, src2w); case SLJIT_LSHR: + case SLJIT_MLSHR: return emit_shift_with_flags(compiler, SHR, HAS_FLAGS(op), dst, dstw, src1, src1w, src2, src2w); case SLJIT_ASHR: + case SLJIT_MASHR: return emit_shift_with_flags(compiler, SAR, HAS_FLAGS(op), dst, dstw, src1, src1w, src2, src2w); + case SLJIT_ROTL: + return emit_shift_with_flags(compiler, ROL, 0, + dst, dstw, src1, src1w, src2, src2w); + case SLJIT_ROTR: + return emit_shift_with_flags(compiler, ROR, 0, + dst, dstw, src1, src1w, src2, src2w); } return SLJIT_SUCCESS; @@ -2312,10 +2494,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2u(struct sljit_compiler *compil CHECK(check_sljit_emit_op2(compiler, op, 1, 0, 0, src1, src1w, src2, src2w)); if (opcode != SLJIT_SUB && opcode != SLJIT_AND) { -#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE) \ - || (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS) - compiler->skip_checks = 1; -#endif + SLJIT_SKIP_CHECKS(compiler); return sljit_emit_op2(compiler, op, TMP_REG1, 0, src1, src1w, src2, src2w); } @@ -2334,6 +2513,122 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2u(struct sljit_compiler *compil return emit_test_binary(compiler, src1, src1w, src2, src2w); } +SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_shift_into(struct sljit_compiler *compiler, sljit_s32 op, + sljit_s32 src_dst, + sljit_s32 src1, sljit_sw src1w, + sljit_s32 src2, sljit_sw src2w) +{ + sljit_s32 restore_ecx = 0; + sljit_s32 is_rotate, is_left; + sljit_u8* inst; + sljit_sw dstw = 0; +#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) + sljit_s32 tmp2 = SLJIT_MEM1(SLJIT_SP); +#else /* !SLJIT_CONFIG_X86_32 */ + sljit_s32 tmp2 = TMP_REG2; +#endif /* SLJIT_CONFIG_X86_32 */ + + CHECK_ERROR(); + CHECK(check_sljit_emit_shift_into(compiler, op, src_dst, src1, src1w, src2, src2w)); + ADJUST_LOCAL_OFFSET(src1, src1w); + ADJUST_LOCAL_OFFSET(src2, src2w); + + CHECK_EXTRA_REGS(src1, src1w, (void)0); + CHECK_EXTRA_REGS(src2, src2w, (void)0); + +#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) + compiler->mode32 = op & SLJIT_32; +#endif + + if (src2 & SLJIT_IMM) { +#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) + src2w &= 0x1f; +#else /* !SLJIT_CONFIG_X86_32 */ + src2w &= (op & SLJIT_32) ? 0x1f : 0x3f; +#endif /* SLJIT_CONFIG_X86_32 */ + + if (src2w == 0) + return SLJIT_SUCCESS; + } + + is_left = (GET_OPCODE(op) == SLJIT_SHL || GET_OPCODE(op) == SLJIT_MSHL); + + is_rotate = (src_dst == src1); + CHECK_EXTRA_REGS(src_dst, dstw, (void)0); + + if (is_rotate) + return emit_shift(compiler, is_left ? ROL : ROR, src_dst, dstw, src1, src1w, src2, src2w); + + if ((src2 & SLJIT_IMM) || src2 == SLJIT_PREF_SHIFT_REG) { + if (!FAST_IS_REG(src1)) { + EMIT_MOV(compiler, TMP_REG1, 0, src1, src1w); + src1 = TMP_REG1; + } + } else if (FAST_IS_REG(src1)) { +#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) + compiler->mode32 = 0; +#endif + EMIT_MOV(compiler, TMP_REG1, 0, SLJIT_PREF_SHIFT_REG, 0); +#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) + compiler->mode32 = op & SLJIT_32; +#endif + EMIT_MOV(compiler, SLJIT_PREF_SHIFT_REG, 0, src2, src2w); + + if (src1 == SLJIT_PREF_SHIFT_REG) + src1 = TMP_REG1; + + if (src_dst == SLJIT_PREF_SHIFT_REG) + src_dst = TMP_REG1; + + restore_ecx = 1; + } else { + EMIT_MOV(compiler, TMP_REG1, 0, src1, src1w); +#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) + compiler->mode32 = 0; +#endif + EMIT_MOV(compiler, tmp2, 0, SLJIT_PREF_SHIFT_REG, 0); +#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) + compiler->mode32 = op & SLJIT_32; +#endif + EMIT_MOV(compiler, SLJIT_PREF_SHIFT_REG, 0, src2, src2w); + + src1 = TMP_REG1; + + if (src_dst == SLJIT_PREF_SHIFT_REG) { + src_dst = tmp2; + SLJIT_ASSERT(dstw == 0); + } + + restore_ecx = 2; + } + + inst = emit_x86_instruction(compiler, 2, src1, 0, src_dst, dstw); + FAIL_IF(!inst); + inst[0] = GROUP_0F; + + if (src2 & SLJIT_IMM) { + inst[1] = U8((is_left ? SHLD : SHRD) - 1); + + /* Immedate argument is added separately. */ + inst = (sljit_u8*)ensure_buf(compiler, 1 + 1); + FAIL_IF(!inst); + INC_SIZE(1); + *inst = U8(src2w); + } else + inst[1] = U8(is_left ? SHLD : SHRD); + +#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) + compiler->mode32 = 0; +#endif + + if (restore_ecx == 1) + return emit_mov(compiler, SLJIT_PREF_SHIFT_REG, 0, TMP_REG1, 0); + if (restore_ecx == 2) + return emit_mov(compiler, SLJIT_PREF_SHIFT_REG, 0, tmp2, 0); + + return SLJIT_SUCCESS; +} + SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_src(struct sljit_compiler *compiler, sljit_s32 op, sljit_s32 src, sljit_sw srcw) { @@ -2516,6 +2811,19 @@ static SLJIT_INLINE sljit_s32 sljit_emit_fop1_cmp(struct sljit_compiler *compile sljit_s32 src1, sljit_sw src1w, sljit_s32 src2, sljit_sw src2w) { + switch (GET_FLAG_TYPE(op)) { + case SLJIT_ORDERED_LESS: + case SLJIT_UNORDERED_OR_GREATER_EQUAL: + case SLJIT_UNORDERED_OR_GREATER: + case SLJIT_ORDERED_LESS_EQUAL: + if (!FAST_IS_REG(src2)) { + FAIL_IF(emit_sse2_load(compiler, op & SLJIT_32, TMP_FREG, src2, src2w)); + src2 = TMP_FREG; + } + + return emit_sse2_logic(compiler, UCOMISD_x_xm, !(op & SLJIT_32), src2, src1, src1w); + } + if (!FAST_IS_REG(src1)) { FAIL_IF(emit_sse2_load(compiler, op & SLJIT_32, TMP_FREG, src1, src1w)); src1 = TMP_FREG; @@ -2769,7 +3077,6 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_flags(struct sljit_compiler *co ADJUST_LOCAL_OFFSET(dst, dstw); CHECK_EXTRA_REGS(dst, dstw, (void)0); - type &= 0xff; /* setcc = jcc + 0x10. */ cond_set = U8(get_jump_code((sljit_uw)type) + 0x10); @@ -2813,10 +3120,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_flags(struct sljit_compiler *co return emit_mov(compiler, dst, dstw, TMP_REG1, 0); } -#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE) \ - || (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS) - compiler->skip_checks = 1; -#endif + SLJIT_SKIP_CHECKS(compiler); return sljit_emit_op2(compiler, op, dst_save, dstw_save, dst_save, dstw_save, TMP_REG1, 0); #else @@ -2839,10 +3143,10 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_flags(struct sljit_compiler *co } /* Low byte is not accessible. */ - if (cpu_has_cmov == -1) + if (cpu_feature_list == 0) get_cpu_features(); - if (cpu_has_cmov) { + if (cpu_feature_list & CPU_FEATURE_CMOV) { EMIT_MOV(compiler, TMP_REG1, 0, SLJIT_IMM, 1); /* a xor reg, reg operation would overwrite the flags. */ EMIT_MOV(compiler, dst, 0, SLJIT_IMM, 0); @@ -2927,10 +3231,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_flags(struct sljit_compiler *co if (GET_OPCODE(op) < SLJIT_ADD) return emit_mov(compiler, dst, dstw, TMP_REG1, 0); -#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE) \ - || (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS) - compiler->skip_checks = 1; -#endif + SLJIT_SKIP_CHECKS(compiler); return sljit_emit_op2(compiler, op, dst_save, dstw_save, dst_save, dstw_save, TMP_REG1, 0); #endif /* SLJIT_CONFIG_X86_64 */ } @@ -2945,7 +3246,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_cmov(struct sljit_compiler *compil CHECK(check_sljit_emit_cmov(compiler, type, dst_reg, src, srcw)); #if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) - dst_reg &= ~SLJIT_32; + type &= ~SLJIT_32; if (!sljit_has_cpu_feature(SLJIT_HAS_CMOV) || (dst_reg >= SLJIT_R3 && dst_reg <= SLJIT_S3)) return sljit_emit_cmov_generic(compiler, type, dst_reg, src, srcw); @@ -2958,8 +3259,8 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_cmov(struct sljit_compiler *compil CHECK_EXTRA_REGS(src, srcw, (void)0); #if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) - compiler->mode32 = dst_reg & SLJIT_32; - dst_reg &= ~SLJIT_32; + compiler->mode32 = type & SLJIT_32; + type &= ~SLJIT_32; #endif if (SLJIT_UNLIKELY(src & SLJIT_IMM)) { @@ -2971,7 +3272,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_cmov(struct sljit_compiler *compil inst = emit_x86_instruction(compiler, 2, dst_reg, 0, src, srcw); FAIL_IF(!inst); *inst++ = GROUP_0F; - *inst = U8(get_jump_code(type & 0xff) - 0x40); + *inst = U8(get_jump_code((sljit_uw)type) - 0x40); return SLJIT_SUCCESS; } |