static sljit_s32 getput_arg()

in pcre/sljit/sljitNativeARM_32.c [1459:1584]


static sljit_s32 getput_arg(struct sljit_compiler *compiler, sljit_s32 inp_flags, sljit_s32 reg, sljit_s32 arg, sljit_sw argw, sljit_s32 next_arg, sljit_sw next_argw)
{
	sljit_s32 tmp_r;
	sljit_sw max_delta;
	sljit_sw sign;
	sljit_uw imm;

	if (arg & SLJIT_IMM) {
		SLJIT_ASSERT(inp_flags & LOAD_DATA);
		return load_immediate(compiler, reg, argw);
	}

	SLJIT_ASSERT(arg & SLJIT_MEM);

	tmp_r = (inp_flags & LOAD_DATA) ? reg : TMP_REG3;
	max_delta = IS_TYPE1_TRANSFER(inp_flags) ? 0xfff : 0xff;

	if ((arg & REG_MASK) == SLJIT_UNUSED) {
		/* Write back is not used. */
		imm = (sljit_uw)(argw - compiler->cache_argw);
		if ((compiler->cache_arg & SLJIT_IMM) && (imm <= (sljit_uw)max_delta || imm >= (sljit_uw)-max_delta)) {
			if (imm <= (sljit_uw)max_delta) {
				sign = 1;
				argw = argw - compiler->cache_argw;
			}
			else {
				sign = 0;
				argw = compiler->cache_argw - argw;
			}

			GETPUT_ARG_DATA_TRANSFER(sign, 0, reg, TMP_REG3, argw);
			return SLJIT_SUCCESS;
		}

		/* With write back, we can create some sophisticated loads, but
		   it is hard to decide whether we should convert downward (0s) or upward (1s). */
		imm = (sljit_uw)(argw - next_argw);
		if ((next_arg & SLJIT_MEM) && (imm <= (sljit_uw)max_delta || imm >= (sljit_uw)-max_delta)) {
			SLJIT_ASSERT(inp_flags & LOAD_DATA);

			compiler->cache_arg = SLJIT_IMM;
			compiler->cache_argw = argw;
			tmp_r = TMP_REG3;
		}

		FAIL_IF(load_immediate(compiler, tmp_r, argw));
		GETPUT_ARG_DATA_TRANSFER(1, 0, reg, tmp_r, 0);
		return SLJIT_SUCCESS;
	}

	if (arg & OFFS_REG_MASK) {
		SLJIT_ASSERT((argw & 0x3) && !(max_delta & 0xf00));
		if (inp_flags & WRITE_BACK)
			tmp_r = arg & REG_MASK;
		FAIL_IF(push_inst(compiler, EMIT_DATA_PROCESS_INS(ADD_DP, 0, tmp_r, arg & REG_MASK, RM(OFFS_REG(arg)) | ((argw & 0x3) << 7))));
		return push_inst(compiler, EMIT_DATA_TRANSFER(inp_flags, 1, 0, reg, tmp_r, TYPE2_TRANSFER_IMM(0)));
	}

	imm = (sljit_uw)(argw - compiler->cache_argw);
	if (compiler->cache_arg == arg && imm <= (sljit_uw)max_delta) {
		SLJIT_ASSERT(!(inp_flags & WRITE_BACK));
		GETPUT_ARG_DATA_TRANSFER(1, 0, reg, TMP_REG3, imm);
		return SLJIT_SUCCESS;
	}
	if (compiler->cache_arg == arg && imm >= (sljit_uw)-max_delta) {
		SLJIT_ASSERT(!(inp_flags & WRITE_BACK));
		imm = (sljit_uw)-(sljit_sw)imm;
		GETPUT_ARG_DATA_TRANSFER(0, 0, reg, TMP_REG3, imm);
		return SLJIT_SUCCESS;
	}

	imm = get_imm(argw & ~max_delta);
	if (imm) {
		TEST_WRITE_BACK();
		FAIL_IF(push_inst(compiler, EMIT_DATA_PROCESS_INS(ADD_DP, 0, tmp_r, arg & REG_MASK, imm)));
		GETPUT_ARG_DATA_TRANSFER(1, inp_flags & WRITE_BACK, reg, tmp_r, argw & max_delta);
		return SLJIT_SUCCESS;
	}

	imm = get_imm(-argw & ~max_delta);
	if (imm) {
		argw = -argw;
		TEST_WRITE_BACK();
		FAIL_IF(push_inst(compiler, EMIT_DATA_PROCESS_INS(SUB_DP, 0, tmp_r, arg & REG_MASK, imm)));
		GETPUT_ARG_DATA_TRANSFER(0, inp_flags & WRITE_BACK, reg, tmp_r, argw & max_delta);
		return SLJIT_SUCCESS;
	}

	if ((compiler->cache_arg & SLJIT_IMM) && compiler->cache_argw == argw) {
		TEST_WRITE_BACK();
		return push_inst(compiler, EMIT_DATA_TRANSFER(inp_flags, 1, inp_flags & WRITE_BACK, reg, arg & REG_MASK, RM(TMP_REG3) | (max_delta & 0xf00 ? SRC2_IMM : 0)));
	}

	if (argw == next_argw && (next_arg & SLJIT_MEM)) {
		SLJIT_ASSERT(inp_flags & LOAD_DATA);
		FAIL_IF(load_immediate(compiler, TMP_REG3, argw));

		compiler->cache_arg = SLJIT_IMM;
		compiler->cache_argw = argw;

		TEST_WRITE_BACK();
		return push_inst(compiler, EMIT_DATA_TRANSFER(inp_flags, 1, inp_flags & WRITE_BACK, reg, arg & REG_MASK, RM(TMP_REG3) | (max_delta & 0xf00 ? SRC2_IMM : 0)));
	}

	imm = (sljit_uw)(argw - next_argw);
	if (arg == next_arg && !(inp_flags & WRITE_BACK) && (imm <= (sljit_uw)max_delta || imm >= (sljit_uw)-max_delta)) {
		SLJIT_ASSERT(inp_flags & LOAD_DATA);
		FAIL_IF(load_immediate(compiler, TMP_REG3, argw));
		FAIL_IF(push_inst(compiler, EMIT_DATA_PROCESS_INS(ADD_DP, 0, TMP_REG3, TMP_REG3, reg_map[arg & REG_MASK])));

		compiler->cache_arg = arg;
		compiler->cache_argw = argw;

		GETPUT_ARG_DATA_TRANSFER(1, 0, reg, TMP_REG3, 0);
		return SLJIT_SUCCESS;
	}

	if ((arg & REG_MASK) == tmp_r) {
		compiler->cache_arg = SLJIT_IMM;
		compiler->cache_argw = argw;
		tmp_r = TMP_REG3;
	}

	FAIL_IF(load_immediate(compiler, tmp_r, argw));
	return push_inst(compiler, EMIT_DATA_TRANSFER(inp_flags, 1, inp_flags & WRITE_BACK, reg, arg & REG_MASK, reg_map[tmp_r] | (max_delta & 0xf00 ? SRC2_IMM : 0)));
}