in pcre/sljit/sljitNativeX86_common.c [2660:2846]
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_flags(struct sljit_compiler *compiler, sljit_s32 op,
sljit_s32 dst, sljit_sw dstw,
sljit_s32 src, sljit_sw srcw,
sljit_s32 type)
{
sljit_u8 *inst;
sljit_u8 cond_set = 0;
#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
sljit_s32 reg;
#else
/* CHECK_EXTRA_REGS migh overwrite these values. */
sljit_s32 dst_save = dst;
sljit_sw dstw_save = dstw;
#endif
CHECK_ERROR();
CHECK(check_sljit_emit_op_flags(compiler, op, dst, dstw, src, srcw, type));
SLJIT_UNUSED_ARG(srcw);
if (dst == SLJIT_UNUSED)
return SLJIT_SUCCESS;
ADJUST_LOCAL_OFFSET(dst, dstw);
CHECK_EXTRA_REGS(dst, dstw, (void)0);
if (SLJIT_UNLIKELY(compiler->flags_saved))
FAIL_IF(emit_restore_flags(compiler, op & SLJIT_KEEP_FLAGS));
type &= 0xff;
/* setcc = jcc + 0x10. */
cond_set = get_jump_code(type) + 0x10;
#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
if (GET_OPCODE(op) == SLJIT_OR && !GET_ALL_FLAGS(op) && FAST_IS_REG(dst) && dst == src) {
inst = (sljit_u8*)ensure_buf(compiler, 1 + 4 + 3);
FAIL_IF(!inst);
INC_SIZE(4 + 3);
/* Set low register to conditional flag. */
*inst++ = (reg_map[TMP_REG1] <= 7) ? REX : REX_B;
*inst++ = GROUP_0F;
*inst++ = cond_set;
*inst++ = MOD_REG | reg_lmap[TMP_REG1];
*inst++ = REX | (reg_map[TMP_REG1] <= 7 ? 0 : REX_R) | (reg_map[dst] <= 7 ? 0 : REX_B);
*inst++ = OR_rm8_r8;
*inst++ = MOD_REG | (reg_lmap[TMP_REG1] << 3) | reg_lmap[dst];
return SLJIT_SUCCESS;
}
reg = (op == SLJIT_MOV && FAST_IS_REG(dst)) ? dst : TMP_REG1;
inst = (sljit_u8*)ensure_buf(compiler, 1 + 4 + 4);
FAIL_IF(!inst);
INC_SIZE(4 + 4);
/* Set low register to conditional flag. */
*inst++ = (reg_map[reg] <= 7) ? REX : REX_B;
*inst++ = GROUP_0F;
*inst++ = cond_set;
*inst++ = MOD_REG | reg_lmap[reg];
*inst++ = REX_W | (reg_map[reg] <= 7 ? 0 : (REX_B | REX_R));
*inst++ = GROUP_0F;
*inst++ = MOVZX_r_rm8;
*inst = MOD_REG | (reg_lmap[reg] << 3) | reg_lmap[reg];
if (reg != TMP_REG1)
return SLJIT_SUCCESS;
if (GET_OPCODE(op) < SLJIT_ADD) {
compiler->mode32 = GET_OPCODE(op) != SLJIT_MOV;
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
return sljit_emit_op2(compiler, op, dst, dstw, dst, dstw, TMP_REG1, 0);
#else /* SLJIT_CONFIG_X86_64 */
if (GET_OPCODE(op) < SLJIT_ADD && FAST_IS_REG(dst)) {
if (reg_map[dst] <= 4) {
/* Low byte is accessible. */
inst = (sljit_u8*)ensure_buf(compiler, 1 + 3 + 3);
FAIL_IF(!inst);
INC_SIZE(3 + 3);
/* Set low byte to conditional flag. */
*inst++ = GROUP_0F;
*inst++ = cond_set;
*inst++ = MOD_REG | reg_map[dst];
*inst++ = GROUP_0F;
*inst++ = MOVZX_r_rm8;
*inst = MOD_REG | (reg_map[dst] << 3) | reg_map[dst];
return SLJIT_SUCCESS;
}
/* Low byte is not accessible. */
if (cpu_has_cmov == -1)
get_cpu_features();
if (cpu_has_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);
inst = (sljit_u8*)ensure_buf(compiler, 1 + 3);
FAIL_IF(!inst);
INC_SIZE(3);
*inst++ = GROUP_0F;
/* cmovcc = setcc - 0x50. */
*inst++ = cond_set - 0x50;
*inst++ = MOD_REG | (reg_map[dst] << 3) | reg_map[TMP_REG1];
return SLJIT_SUCCESS;
}
inst = (sljit_u8*)ensure_buf(compiler, 1 + 1 + 3 + 3 + 1);
FAIL_IF(!inst);
INC_SIZE(1 + 3 + 3 + 1);
*inst++ = XCHG_EAX_r + reg_map[TMP_REG1];
/* Set al to conditional flag. */
*inst++ = GROUP_0F;
*inst++ = cond_set;
*inst++ = MOD_REG | 0 /* eax */;
*inst++ = GROUP_0F;
*inst++ = MOVZX_r_rm8;
*inst++ = MOD_REG | (reg_map[dst] << 3) | 0 /* eax */;
*inst++ = XCHG_EAX_r + reg_map[TMP_REG1];
return SLJIT_SUCCESS;
}
if (GET_OPCODE(op) == SLJIT_OR && !GET_ALL_FLAGS(op) && FAST_IS_REG(dst) && dst == src && reg_map[dst] <= 4) {
SLJIT_COMPILE_ASSERT(reg_map[SLJIT_R0] == 0, scratch_reg1_must_be_eax);
if (dst != SLJIT_R0) {
inst = (sljit_u8*)ensure_buf(compiler, 1 + 1 + 3 + 2 + 1);
FAIL_IF(!inst);
INC_SIZE(1 + 3 + 2 + 1);
/* Set low register to conditional flag. */
*inst++ = XCHG_EAX_r + reg_map[TMP_REG1];
*inst++ = GROUP_0F;
*inst++ = cond_set;
*inst++ = MOD_REG | 0 /* eax */;
*inst++ = OR_rm8_r8;
*inst++ = MOD_REG | (0 /* eax */ << 3) | reg_map[dst];
*inst++ = XCHG_EAX_r + reg_map[TMP_REG1];
}
else {
inst = (sljit_u8*)ensure_buf(compiler, 1 + 2 + 3 + 2 + 2);
FAIL_IF(!inst);
INC_SIZE(2 + 3 + 2 + 2);
/* Set low register to conditional flag. */
*inst++ = XCHG_r_rm;
*inst++ = MOD_REG | (1 /* ecx */ << 3) | reg_map[TMP_REG1];
*inst++ = GROUP_0F;
*inst++ = cond_set;
*inst++ = MOD_REG | 1 /* ecx */;
*inst++ = OR_rm8_r8;
*inst++ = MOD_REG | (1 /* ecx */ << 3) | 0 /* eax */;
*inst++ = XCHG_r_rm;
*inst++ = MOD_REG | (1 /* ecx */ << 3) | reg_map[TMP_REG1];
}
return SLJIT_SUCCESS;
}
/* Set TMP_REG1 to the bit. */
inst = (sljit_u8*)ensure_buf(compiler, 1 + 1 + 3 + 3 + 1);
FAIL_IF(!inst);
INC_SIZE(1 + 3 + 3 + 1);
*inst++ = XCHG_EAX_r + reg_map[TMP_REG1];
/* Set al to conditional flag. */
*inst++ = GROUP_0F;
*inst++ = cond_set;
*inst++ = MOD_REG | 0 /* eax */;
*inst++ = GROUP_0F;
*inst++ = MOVZX_r_rm8;
*inst++ = MOD_REG | (0 << 3) /* eax */ | 0 /* eax */;
*inst++ = XCHG_EAX_r + reg_map[TMP_REG1];
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
return sljit_emit_op2(compiler, op, dst_save, dstw_save, dst_save, dstw_save, TMP_REG1, 0);
#endif /* SLJIT_CONFIG_X86_64 */
}