static sljit_s32 getput_arg()

in pcre/sljit/sljitNativeARM_64.c [909:1041]


static sljit_s32 getput_arg(struct sljit_compiler *compiler, sljit_s32 flags, sljit_s32 reg,
	sljit_s32 arg, sljit_sw argw, sljit_s32 next_arg, sljit_sw next_argw)
{
	sljit_u32 shift = MEM_SIZE_SHIFT(flags);
	sljit_s32 tmp_r, other_r;
	sljit_sw diff;

	SLJIT_ASSERT(arg & SLJIT_MEM);
	if (!(next_arg & SLJIT_MEM)) {
		next_arg = 0;
		next_argw = 0;
	}

	tmp_r = (flags & STORE) ? TMP_REG3 : reg;

	if (SLJIT_UNLIKELY((flags & UPDATE) && (arg & REG_MASK))) {
		/* Update only applies if a base register exists. */
		other_r = OFFS_REG(arg);
		if (!other_r) {
			other_r = arg & REG_MASK;
			if (other_r != reg && argw >= 0 && argw <= 0xffffff) {
				if ((argw & 0xfff) != 0)
					FAIL_IF(push_inst(compiler, ADDI | RD(other_r) | RN(other_r) | ((argw & 0xfff) << 10)));
				if (argw >> 12)
					FAIL_IF(push_inst(compiler, ADDI | (1 << 22) | RD(other_r) | RN(other_r) | ((argw >> 12) << 10)));
				return push_inst(compiler, sljit_mem_imm[flags & 0x3] | (shift << 30) | RT(reg) | RN(other_r));
			}
			else if (other_r != reg && argw < 0 && argw >= -0xffffff) {
				argw = -argw;
				if ((argw & 0xfff) != 0)
					FAIL_IF(push_inst(compiler, SUBI | RD(other_r) | RN(other_r) | ((argw & 0xfff) << 10)));
				if (argw >> 12)
					FAIL_IF(push_inst(compiler, SUBI | (1 << 22) | RD(other_r) | RN(other_r) | ((argw >> 12) << 10)));
				return push_inst(compiler, sljit_mem_imm[flags & 0x3] | (shift << 30) | RT(reg) | RN(other_r));
			}

			if (compiler->cache_arg == SLJIT_MEM) {
				if (argw == compiler->cache_argw) {
					other_r = TMP_REG3;
					argw = 0;
				}
				else if (emit_set_delta(compiler, TMP_REG3, TMP_REG3, argw - compiler->cache_argw) != SLJIT_ERR_UNSUPPORTED) {
					FAIL_IF(compiler->error);
					compiler->cache_argw = argw;
					other_r = TMP_REG3;
					argw = 0;
				}
			}

			if (argw) {
				FAIL_IF(load_immediate(compiler, TMP_REG3, argw));
				compiler->cache_arg = SLJIT_MEM;
				compiler->cache_argw = argw;
				other_r = TMP_REG3;
				argw = 0;
			}
		}

		/* No caching here. */
		arg &= REG_MASK;
		argw &= 0x3;
		if (!argw || argw == shift) {
			FAIL_IF(push_inst(compiler, sljit_mem_reg[flags & 0x3] | (shift << 30) | RT(reg) | RN(arg) | RM(other_r) | (argw ? (1 << 12) : 0)));
			return push_inst(compiler, ADD | RD(arg) | RN(arg) | RM(other_r) | (argw << 10));
		}
		if (arg != reg) {
			FAIL_IF(push_inst(compiler, ADD | RD(arg) | RN(arg) | RM(other_r) | (argw << 10)));
			return push_inst(compiler, sljit_mem_imm[flags & 0x3] | (shift << 30) | RT(reg) | RN(arg));
		}
		FAIL_IF(push_inst(compiler, ADD | RD(TMP_LR) | RN(arg) | RM(other_r) | (argw << 10)));
		FAIL_IF(push_inst(compiler, sljit_mem_imm[flags & 0x3] | (shift << 30) | RT(reg) | RN(TMP_LR)));
		return push_inst(compiler, ORR | RD(arg) | RN(TMP_ZERO) | RM(TMP_LR));
	}

	if (arg & OFFS_REG_MASK) {
		other_r = OFFS_REG(arg);
		arg &= REG_MASK;
		FAIL_IF(push_inst(compiler, ADD | RD(tmp_r) | RN(arg) | RM(other_r) | ((argw & 0x3) << 10)));
		return push_inst(compiler, sljit_mem_imm[flags & 0x3] | (shift << 30) | RT(reg) | RN(tmp_r));
	}

	if (compiler->cache_arg == arg) {
		diff = argw - compiler->cache_argw;
		if (diff <= 255 && diff >= -256)
			return push_inst(compiler, sljit_mem_simm[flags & 0x3] | (shift << 30)
				| RT(reg) | RN(TMP_REG3) | ((diff & 0x1ff) << 12));
		if (emit_set_delta(compiler, TMP_REG3, TMP_REG3, diff) != SLJIT_ERR_UNSUPPORTED) {
			FAIL_IF(compiler->error);
			return push_inst(compiler, sljit_mem_imm[flags & 0x3] | (shift << 30) | RT(reg) | RN(arg));
		}
	}

	if (argw >= 0 && argw <= 0xffffff && (argw & ((1 << shift) - 1)) == 0) {
		FAIL_IF(push_inst(compiler, ADDI | (1 << 22) | RD(tmp_r) | RN(arg & REG_MASK) | ((argw >> 12) << 10)));
		return push_inst(compiler, sljit_mem_imm[flags & 0x3] | (shift << 30)
			| RT(reg) | RN(tmp_r) | ((argw & 0xfff) << (10 - shift)));
	}

	diff = argw - next_argw;
	next_arg = (arg & REG_MASK) && (arg == next_arg) && diff <= 0xfff && diff >= -0xfff && diff != 0;
	arg &= REG_MASK;

	if (arg && compiler->cache_arg == SLJIT_MEM) {
		if (compiler->cache_argw == argw)
			return push_inst(compiler, sljit_mem_reg[flags & 0x3] | (shift << 30) | RT(reg) | RN(arg) | RM(TMP_REG3));
		if (emit_set_delta(compiler, TMP_REG3, TMP_REG3, argw - compiler->cache_argw) != SLJIT_ERR_UNSUPPORTED) {
			FAIL_IF(compiler->error);
			compiler->cache_argw = argw;
			return push_inst(compiler, sljit_mem_reg[flags & 0x3] | (shift << 30) | RT(reg) | RN(arg) | RM(TMP_REG3));
		}
	}

	compiler->cache_argw = argw;
	if (next_arg && emit_set_delta(compiler, TMP_REG3, arg, argw) != SLJIT_ERR_UNSUPPORTED) {
		FAIL_IF(compiler->error);
		compiler->cache_arg = SLJIT_MEM | arg;
		arg = 0;
	}
	else {
		FAIL_IF(load_immediate(compiler, TMP_REG3, argw));
		compiler->cache_arg = SLJIT_MEM;

		if (next_arg) {
			FAIL_IF(push_inst(compiler, ADD | RD(TMP_REG3) | RN(TMP_REG3) | RM(arg)));
			compiler->cache_arg = SLJIT_MEM | arg;
			arg = 0;
		}
	}

	if (arg)
		return push_inst(compiler, sljit_mem_reg[flags & 0x3] | (shift << 30) | RT(reg) | RN(arg) | RM(TMP_REG3));
	return push_inst(compiler, sljit_mem_imm[flags & 0x3] | (shift << 30) | RT(reg) | RN(TMP_REG3));
}