static SLJIT_INLINE sljit_s32 emit_single_op()

in pcre/sljit/sljitNativeTILEGX_64.c [1585:1957]


static SLJIT_INLINE sljit_s32 emit_single_op(struct sljit_compiler *compiler, sljit_s32 op, sljit_s32 flags, sljit_s32 dst, sljit_s32 src1, sljit_sw src2)
{
	sljit_s32 overflow_ra = 0;

	switch (GET_OPCODE(op)) {
	case SLJIT_MOV:
	case SLJIT_MOV_P:
		SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM));
		if (dst != src2)
			return ADD(reg_map[dst], reg_map[src2], ZERO);
		return SLJIT_SUCCESS;

	case SLJIT_MOV_U32:
	case SLJIT_MOV_S32:
		SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM));
		if ((flags & (REG_DEST | REG2_SOURCE)) == (REG_DEST | REG2_SOURCE)) {
			if (op == SLJIT_MOV_S32)
				return BFEXTS(reg_map[dst], reg_map[src2], 0, 31);

			return BFEXTU(reg_map[dst], reg_map[src2], 0, 31);
		} else if (dst != src2) {
			SLJIT_ASSERT(src2 == 0);
			return ADD(reg_map[dst], reg_map[src2], ZERO);
		}

		return SLJIT_SUCCESS;

	case SLJIT_MOV_U8:
	case SLJIT_MOV_S8:
		SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM));
		if ((flags & (REG_DEST | REG2_SOURCE)) == (REG_DEST | REG2_SOURCE)) {
			if (op == SLJIT_MOV_S8)
				return BFEXTS(reg_map[dst], reg_map[src2], 0, 7);

			return BFEXTU(reg_map[dst], reg_map[src2], 0, 7);
		} else if (dst != src2) {
			SLJIT_ASSERT(src2 == 0);
			return ADD(reg_map[dst], reg_map[src2], ZERO);
		}

		return SLJIT_SUCCESS;

	case SLJIT_MOV_U16:
	case SLJIT_MOV_S16:
		SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM));
		if ((flags & (REG_DEST | REG2_SOURCE)) == (REG_DEST | REG2_SOURCE)) {
			if (op == SLJIT_MOV_S16)
				return BFEXTS(reg_map[dst], reg_map[src2], 0, 15);

			return BFEXTU(reg_map[dst], reg_map[src2], 0, 15);
		} else if (dst != src2) {
			SLJIT_ASSERT(src2 == 0);
			return ADD(reg_map[dst], reg_map[src2], ZERO);
		}

		return SLJIT_SUCCESS;

	case SLJIT_NOT:
		SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM));
		if (op & SLJIT_SET_E)
			FAIL_IF(NOR(EQUAL_FLAG, reg_map[src2], reg_map[src2]));
		if (CHECK_FLAGS(SLJIT_SET_E))
			FAIL_IF(NOR(reg_map[dst], reg_map[src2], reg_map[src2]));

		return SLJIT_SUCCESS;

	case SLJIT_CLZ:
		SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM));
		if (op & SLJIT_SET_E)
			FAIL_IF(CLZ(EQUAL_FLAG, reg_map[src2]));
		if (CHECK_FLAGS(SLJIT_SET_E))
			FAIL_IF(CLZ(reg_map[dst], reg_map[src2]));

		return SLJIT_SUCCESS;

	case SLJIT_ADD:
		if (flags & SRC2_IMM) {
			if (op & SLJIT_SET_O) {
				FAIL_IF(SHRUI(TMP_EREG1, reg_map[src1], 63));
				if (src2 < 0)
					FAIL_IF(XORI(TMP_EREG1, TMP_EREG1, 1));
			}

			if (op & SLJIT_SET_E)
				FAIL_IF(ADDLI(EQUAL_FLAG, reg_map[src1], src2));

			if (op & SLJIT_SET_C) {
				if (src2 >= 0)
					FAIL_IF(ORI(ULESS_FLAG ,reg_map[src1], src2));
				else {
					FAIL_IF(ADDLI(ULESS_FLAG ,ZERO, src2));
					FAIL_IF(OR(ULESS_FLAG,reg_map[src1],ULESS_FLAG));
				}
			}

			/* dst may be the same as src1 or src2. */
			if (CHECK_FLAGS(SLJIT_SET_E))
				FAIL_IF(ADDLI(reg_map[dst], reg_map[src1], src2));

			if (op & SLJIT_SET_O) {
				FAIL_IF(SHRUI(OVERFLOW_FLAG, reg_map[dst], 63));

				if (src2 < 0)
					FAIL_IF(XORI(OVERFLOW_FLAG, OVERFLOW_FLAG, 1));
			}
		} else {
			if (op & SLJIT_SET_O) {
				FAIL_IF(XOR(TMP_EREG1, reg_map[src1], reg_map[src2]));
				FAIL_IF(SHRUI(TMP_EREG1, TMP_EREG1, 63));

				if (src1 != dst)
					overflow_ra = reg_map[src1];
				else if (src2 != dst)
					overflow_ra = reg_map[src2];
				else {
					/* Rare ocasion. */
					FAIL_IF(ADD(TMP_EREG2, reg_map[src1], ZERO));
					overflow_ra = TMP_EREG2;
				}
			}

			if (op & SLJIT_SET_E)
				FAIL_IF(ADD(EQUAL_FLAG ,reg_map[src1], reg_map[src2]));

			if (op & SLJIT_SET_C)
				FAIL_IF(OR(ULESS_FLAG,reg_map[src1], reg_map[src2]));

			/* dst may be the same as src1 or src2. */
			if (CHECK_FLAGS(SLJIT_SET_E))
				FAIL_IF(ADD(reg_map[dst],reg_map[src1], reg_map[src2]));

			if (op & SLJIT_SET_O) {
				FAIL_IF(XOR(OVERFLOW_FLAG,reg_map[dst], overflow_ra));
				FAIL_IF(SHRUI(OVERFLOW_FLAG, OVERFLOW_FLAG, 63));
			}
		}

		/* a + b >= a | b (otherwise, the carry should be set to 1). */
		if (op & SLJIT_SET_C)
			FAIL_IF(CMPLTU(ULESS_FLAG ,reg_map[dst] ,ULESS_FLAG));

		if (op & SLJIT_SET_O)
			return CMOVNEZ(OVERFLOW_FLAG, TMP_EREG1, ZERO);

		return SLJIT_SUCCESS;

	case SLJIT_ADDC:
		if (flags & SRC2_IMM) {
			if (op & SLJIT_SET_C) {
				if (src2 >= 0)
					FAIL_IF(ORI(TMP_EREG1, reg_map[src1], src2));
				else {
					FAIL_IF(ADDLI(TMP_EREG1, ZERO, src2));
					FAIL_IF(OR(TMP_EREG1, reg_map[src1], TMP_EREG1));
				}
			}

			FAIL_IF(ADDLI(reg_map[dst], reg_map[src1], src2));

		} else {
			if (op & SLJIT_SET_C)
				FAIL_IF(OR(TMP_EREG1, reg_map[src1], reg_map[src2]));

			/* dst may be the same as src1 or src2. */
			FAIL_IF(ADD(reg_map[dst], reg_map[src1], reg_map[src2]));
		}

		if (op & SLJIT_SET_C)
			FAIL_IF(CMPLTU(TMP_EREG1, reg_map[dst], TMP_EREG1));

		FAIL_IF(ADD(reg_map[dst], reg_map[dst], ULESS_FLAG));

		if (!(op & SLJIT_SET_C))
			return SLJIT_SUCCESS;

		/* Set TMP_EREG2 (dst == 0) && (ULESS_FLAG == 1). */
		FAIL_IF(CMPLTUI(TMP_EREG2, reg_map[dst], 1));
		FAIL_IF(AND(TMP_EREG2, TMP_EREG2, ULESS_FLAG));
		/* Set carry flag. */
		return OR(ULESS_FLAG, TMP_EREG2, TMP_EREG1);

	case SLJIT_SUB:
		if ((flags & SRC2_IMM) && ((op & (SLJIT_SET_U | SLJIT_SET_S)) || src2 == SIMM_16BIT_MIN)) {
			FAIL_IF(ADDLI(TMP_REG2_mapped, ZERO, src2));
			src2 = TMP_REG2;
			flags &= ~SRC2_IMM;
		}

		if (flags & SRC2_IMM) {
			if (op & SLJIT_SET_O) {
				FAIL_IF(SHRUI(TMP_EREG1,reg_map[src1], 63));

				if (src2 < 0)
					FAIL_IF(XORI(TMP_EREG1, TMP_EREG1, 1));

				if (src1 != dst)
					overflow_ra = reg_map[src1];
				else {
					/* Rare ocasion. */
					FAIL_IF(ADD(TMP_EREG2, reg_map[src1], ZERO));
					overflow_ra = TMP_EREG2;
				}
			}

			if (op & SLJIT_SET_E)
				FAIL_IF(ADDLI(EQUAL_FLAG, reg_map[src1], -src2));

			if (op & SLJIT_SET_C) {
				FAIL_IF(load_immediate(compiler, ADDR_TMP_mapped, src2));
				FAIL_IF(CMPLTU(ULESS_FLAG, reg_map[src1], ADDR_TMP_mapped));
			}

			/* dst may be the same as src1 or src2. */
			if (CHECK_FLAGS(SLJIT_SET_E))
				FAIL_IF(ADDLI(reg_map[dst], reg_map[src1], -src2));

		} else {

			if (op & SLJIT_SET_O) {
				FAIL_IF(XOR(TMP_EREG1, reg_map[src1], reg_map[src2]));
				FAIL_IF(SHRUI(TMP_EREG1, TMP_EREG1, 63));

				if (src1 != dst)
					overflow_ra = reg_map[src1];
				else {
					/* Rare ocasion. */
					FAIL_IF(ADD(TMP_EREG2, reg_map[src1], ZERO));
					overflow_ra = TMP_EREG2;
				}
			}

			if (op & SLJIT_SET_E)
				FAIL_IF(SUB(EQUAL_FLAG, reg_map[src1], reg_map[src2]));

			if (op & (SLJIT_SET_U | SLJIT_SET_C))
				FAIL_IF(CMPLTU(ULESS_FLAG, reg_map[src1], reg_map[src2]));

			if (op & SLJIT_SET_U)
				FAIL_IF(CMPLTU(UGREATER_FLAG, reg_map[src2], reg_map[src1]));

			if (op & SLJIT_SET_S) {
				FAIL_IF(CMPLTS(LESS_FLAG ,reg_map[src1] ,reg_map[src2]));
				FAIL_IF(CMPLTS(GREATER_FLAG ,reg_map[src2] ,reg_map[src1]));
			}

			/* dst may be the same as src1 or src2. */
			if (CHECK_FLAGS(SLJIT_SET_E | SLJIT_SET_U | SLJIT_SET_S | SLJIT_SET_C))
				FAIL_IF(SUB(reg_map[dst], reg_map[src1], reg_map[src2]));
		}

		if (op & SLJIT_SET_O) {
			FAIL_IF(XOR(OVERFLOW_FLAG, reg_map[dst], overflow_ra));
			FAIL_IF(SHRUI(OVERFLOW_FLAG, OVERFLOW_FLAG, 63));
			return CMOVEQZ(OVERFLOW_FLAG, TMP_EREG1, ZERO);
		}

		return SLJIT_SUCCESS;

	case SLJIT_SUBC:
		if ((flags & SRC2_IMM) && src2 == SIMM_16BIT_MIN) {
			FAIL_IF(ADDLI(TMP_REG2_mapped, ZERO, src2));
			src2 = TMP_REG2;
			flags &= ~SRC2_IMM;
		}

		if (flags & SRC2_IMM) {
			if (op & SLJIT_SET_C) {
				FAIL_IF(load_immediate(compiler, ADDR_TMP_mapped, -src2));
				FAIL_IF(CMPLTU(TMP_EREG1, reg_map[src1], ADDR_TMP_mapped));
			}

			/* dst may be the same as src1 or src2. */
			FAIL_IF(ADDLI(reg_map[dst], reg_map[src1], -src2));

		} else {
			if (op & SLJIT_SET_C)
				FAIL_IF(CMPLTU(TMP_EREG1, reg_map[src1], reg_map[src2]));
				/* dst may be the same as src1 or src2. */
			FAIL_IF(SUB(reg_map[dst], reg_map[src1], reg_map[src2]));
		}

		if (op & SLJIT_SET_C)
			FAIL_IF(CMOVEQZ(TMP_EREG1, reg_map[dst], ULESS_FLAG));

		FAIL_IF(SUB(reg_map[dst], reg_map[dst], ULESS_FLAG));

		if (op & SLJIT_SET_C)
			FAIL_IF(ADD(ULESS_FLAG, TMP_EREG1, ZERO));

		return SLJIT_SUCCESS;

	case SLJIT_MUL:
		if (flags & SRC2_IMM) {
			FAIL_IF(load_immediate(compiler, TMP_REG2_mapped, src2));
			src2 = TMP_REG2;
			flags &= ~SRC2_IMM;
		}

		FAIL_IF(MUL(reg_map[dst], reg_map[src1], reg_map[src2]));

		return SLJIT_SUCCESS;

#define EMIT_LOGICAL(op_imm, op_norm) \
	if (flags & SRC2_IMM) { \
		FAIL_IF(load_immediate(compiler, ADDR_TMP_mapped, src2)); \
		if (op & SLJIT_SET_E) \
			FAIL_IF(push_3_buffer( \
				compiler, op_norm, EQUAL_FLAG, reg_map[src1], \
				ADDR_TMP_mapped, __LINE__)); \
		if (CHECK_FLAGS(SLJIT_SET_E)) \
			FAIL_IF(push_3_buffer( \
				compiler, op_norm, reg_map[dst], reg_map[src1], \
				ADDR_TMP_mapped, __LINE__)); \
	} else { \
		if (op & SLJIT_SET_E) \
			FAIL_IF(push_3_buffer( \
				compiler, op_norm, EQUAL_FLAG, reg_map[src1], \
				reg_map[src2], __LINE__)); \
		if (CHECK_FLAGS(SLJIT_SET_E)) \
			FAIL_IF(push_3_buffer( \
				compiler, op_norm, reg_map[dst], reg_map[src1], \
				reg_map[src2], __LINE__)); \
	}

	case SLJIT_AND:
		EMIT_LOGICAL(TILEGX_OPC_ANDI, TILEGX_OPC_AND);
		return SLJIT_SUCCESS;

	case SLJIT_OR:
		EMIT_LOGICAL(TILEGX_OPC_ORI, TILEGX_OPC_OR);
		return SLJIT_SUCCESS;

	case SLJIT_XOR:
		EMIT_LOGICAL(TILEGX_OPC_XORI, TILEGX_OPC_XOR);
		return SLJIT_SUCCESS;

#define EMIT_SHIFT(op_imm, op_norm) \
	if (flags & SRC2_IMM) { \
		if (op & SLJIT_SET_E) \
			FAIL_IF(push_3_buffer( \
				compiler, op_imm, EQUAL_FLAG, reg_map[src1], \
				src2 & 0x3F, __LINE__)); \
		if (CHECK_FLAGS(SLJIT_SET_E)) \
			FAIL_IF(push_3_buffer( \
				compiler, op_imm, reg_map[dst], reg_map[src1], \
				src2 & 0x3F, __LINE__)); \
	} else { \
		if (op & SLJIT_SET_E) \
			FAIL_IF(push_3_buffer( \
				compiler, op_norm, EQUAL_FLAG, reg_map[src1], \
				reg_map[src2], __LINE__)); \
		if (CHECK_FLAGS(SLJIT_SET_E)) \
			FAIL_IF(push_3_buffer( \
				compiler, op_norm, reg_map[dst], reg_map[src1], \
				reg_map[src2], __LINE__)); \
	}

	case SLJIT_SHL:
		EMIT_SHIFT(TILEGX_OPC_SHLI, TILEGX_OPC_SHL);
		return SLJIT_SUCCESS;

	case SLJIT_LSHR:
		EMIT_SHIFT(TILEGX_OPC_SHRUI, TILEGX_OPC_SHRU);
		return SLJIT_SUCCESS;

	case SLJIT_ASHR:
		EMIT_SHIFT(TILEGX_OPC_SHRSI, TILEGX_OPC_SHRS);
		return SLJIT_SUCCESS;
	}

	SLJIT_ASSERT_STOP();
	return SLJIT_SUCCESS;
}