in pcre/sljit/sljitNativeARM_32.c [1602:1790]
static sljit_s32 emit_op(struct sljit_compiler *compiler, sljit_s32 op, sljit_s32 inp_flags,
sljit_s32 dst, sljit_sw dstw,
sljit_s32 src1, sljit_sw src1w,
sljit_s32 src2, sljit_sw src2w)
{
/* arg1 goes to TMP_REG1 or src reg
arg2 goes to TMP_REG2, imm or src reg
TMP_REG3 can be used for caching
result goes to TMP_REG2, so put result can use TMP_REG1 and TMP_REG3. */
/* We prefers register and simple consts. */
sljit_s32 dst_r;
sljit_s32 src1_r;
sljit_s32 src2_r = 0;
sljit_s32 sugg_src2_r = TMP_REG2;
sljit_s32 flags = GET_FLAGS(op) ? SET_FLAGS : 0;
compiler->cache_arg = 0;
compiler->cache_argw = 0;
/* Destination check. */
if (SLJIT_UNLIKELY(dst == SLJIT_UNUSED)) {
if (op >= SLJIT_MOV && op <= SLJIT_MOVU_S32 && !(src2 & SLJIT_MEM))
return SLJIT_SUCCESS;
dst_r = TMP_REG2;
}
else if (FAST_IS_REG(dst)) {
dst_r = dst;
flags |= REG_DEST;
if (op >= SLJIT_MOV && op <= SLJIT_MOVU_S32)
sugg_src2_r = dst_r;
}
else {
SLJIT_ASSERT(dst & SLJIT_MEM);
if (getput_arg_fast(compiler, inp_flags | ARG_TEST, TMP_REG2, dst, dstw)) {
flags |= FAST_DEST;
dst_r = TMP_REG2;
}
else {
flags |= SLOW_DEST;
dst_r = 0;
}
}
/* Source 1. */
if (FAST_IS_REG(src1))
src1_r = src1;
else if (FAST_IS_REG(src2)) {
flags |= ARGS_SWAPPED;
src1_r = src2;
src2 = src1;
src2w = src1w;
}
else do { /* do { } while(0) is used because of breaks. */
src1_r = 0;
if ((inp_flags & ALLOW_ANY_IMM) && (src1 & SLJIT_IMM)) {
/* The second check will generate a hit. */
src2_r = get_imm(src1w);
if (src2_r) {
flags |= ARGS_SWAPPED;
src1 = src2;
src1w = src2w;
break;
}
if (inp_flags & ALLOW_INV_IMM) {
src2_r = get_imm(~src1w);
if (src2_r) {
flags |= ARGS_SWAPPED | INV_IMM;
src1 = src2;
src1w = src2w;
break;
}
}
if (GET_OPCODE(op) == SLJIT_ADD) {
src2_r = get_imm(-src1w);
if (src2_r) {
/* Note: ARGS_SWAPPED is intentionally not applied! */
src1 = src2;
src1w = src2w;
op = SLJIT_SUB | GET_ALL_FLAGS(op);
break;
}
}
}
if (getput_arg_fast(compiler, inp_flags | LOAD_DATA, TMP_REG1, src1, src1w)) {
FAIL_IF(compiler->error);
src1_r = TMP_REG1;
}
} while (0);
/* Source 2. */
if (src2_r == 0) {
if (FAST_IS_REG(src2)) {
src2_r = src2;
flags |= REG_SOURCE;
if (!(flags & REG_DEST) && op >= SLJIT_MOV && op <= SLJIT_MOVU_S32)
dst_r = src2_r;
}
else do { /* do { } while(0) is used because of breaks. */
if ((inp_flags & ALLOW_ANY_IMM) && (src2 & SLJIT_IMM)) {
src2_r = get_imm(src2w);
if (src2_r)
break;
if (inp_flags & ALLOW_INV_IMM) {
src2_r = get_imm(~src2w);
if (src2_r) {
flags |= INV_IMM;
break;
}
}
if (GET_OPCODE(op) == SLJIT_ADD) {
src2_r = get_imm(-src2w);
if (src2_r) {
op = SLJIT_SUB | GET_ALL_FLAGS(op);
flags &= ~ARGS_SWAPPED;
break;
}
}
if (GET_OPCODE(op) == SLJIT_SUB && !(flags & ARGS_SWAPPED)) {
src2_r = get_imm(-src2w);
if (src2_r) {
op = SLJIT_ADD | GET_ALL_FLAGS(op);
flags &= ~ARGS_SWAPPED;
break;
}
}
}
/* src2_r is 0. */
if (getput_arg_fast(compiler, inp_flags | LOAD_DATA, sugg_src2_r, src2, src2w)) {
FAIL_IF(compiler->error);
src2_r = sugg_src2_r;
}
} while (0);
}
/* src1_r, src2_r and dst_r can be zero (=unprocessed) or non-zero.
If they are zero, they must not be registers. */
if (src1_r == 0 && src2_r == 0 && dst_r == 0) {
if (!can_cache(src1, src1w, src2, src2w) && can_cache(src1, src1w, dst, dstw)) {
SLJIT_ASSERT(!(flags & ARGS_SWAPPED));
flags |= ARGS_SWAPPED;
FAIL_IF(getput_arg(compiler, inp_flags | LOAD_DATA, TMP_REG1, src2, src2w, src1, src1w));
FAIL_IF(getput_arg(compiler, inp_flags | LOAD_DATA, TMP_REG2, src1, src1w, dst, dstw));
}
else {
FAIL_IF(getput_arg(compiler, inp_flags | LOAD_DATA, TMP_REG1, src1, src1w, src2, src2w));
FAIL_IF(getput_arg(compiler, inp_flags | LOAD_DATA, TMP_REG2, src2, src2w, dst, dstw));
}
src1_r = TMP_REG1;
src2_r = TMP_REG2;
}
else if (src1_r == 0 && src2_r == 0) {
FAIL_IF(getput_arg(compiler, inp_flags | LOAD_DATA, TMP_REG1, src1, src1w, src2, src2w));
src1_r = TMP_REG1;
}
else if (src1_r == 0 && dst_r == 0) {
FAIL_IF(getput_arg(compiler, inp_flags | LOAD_DATA, TMP_REG1, src1, src1w, dst, dstw));
src1_r = TMP_REG1;
}
else if (src2_r == 0 && dst_r == 0) {
FAIL_IF(getput_arg(compiler, inp_flags | LOAD_DATA, sugg_src2_r, src2, src2w, dst, dstw));
src2_r = sugg_src2_r;
}
if (dst_r == 0)
dst_r = TMP_REG2;
if (src1_r == 0) {
FAIL_IF(getput_arg(compiler, inp_flags | LOAD_DATA, TMP_REG1, src1, src1w, 0, 0));
src1_r = TMP_REG1;
}
if (src2_r == 0) {
FAIL_IF(getput_arg(compiler, inp_flags | LOAD_DATA, sugg_src2_r, src2, src2w, 0, 0));
src2_r = sugg_src2_r;
}
FAIL_IF(emit_single_op(compiler, op, flags, dst_r, src1_r, src2_r));
if (flags & (FAST_DEST | SLOW_DEST)) {
if (flags & FAST_DEST)
FAIL_IF(getput_arg_fast(compiler, inp_flags, dst_r, dst, dstw));
else
FAIL_IF(getput_arg(compiler, inp_flags, dst_r, dst, dstw, 0, 0));
}
return SLJIT_SUCCESS;
}