OPTAB_DIRECT);
}
+/* Helper function for loongarch_extend_comparands to Sign-extend the OP.
+ However if the OP is SI subreg promoted with an inner DI, such as
+ (subreg/s/v:SI (reg/v:DI) 0)
+ just peel off the SUBREG to get DI, avoiding extraneous extension.
+ This modification refers to riscv's commit r14-5506. */
+
+static void
+loongarch_sign_extend_if_subreg_prom_p (rtx *op)
+{
+ if (SUBREG_P (*op)
+ && SUBREG_PROMOTED_VAR_P (*op)
+ && SUBREG_PROMOTED_SIGNED_P (*op)
+ && REG_P (XEXP (*op, 0))
+ && (GET_MODE_SIZE (GET_MODE (XEXP (*op, 0)))
+ == GET_MODE_SIZE (word_mode)))
+ *op = XEXP (*op, 0);
+ else
+ *op = gen_rtx_SIGN_EXTEND (word_mode, *op);
+}
+
/* Sign- or zero-extend OP0 and OP1 for integer comparisons. */
static void
}
else
{
- *op0 = gen_rtx_SIGN_EXTEND (word_mode, *op0);
+ loongarch_sign_extend_if_subreg_prom_p (op0);
/* Regardless of whether *op1 is any immediate number, it is not
loaded into the register, in order to facilitate the generation
of slt{u}i. */
if (!CONST_INT_P (*op1))
- *op1 = gen_rtx_SIGN_EXTEND (word_mode, *op1);
+ loongarch_sign_extend_if_subreg_prom_p (op1);
}
}
}
-
/* Convert a comparison into something that can be used in a branch. On
entry, *OP0 and *OP1 are the values being compared and *CODE is the code
used to compare them. Update them to describe the final comparison. */
enum rtx_code code = GET_CODE (operands[1]);
rtx op0 = XEXP (operands[1], 0);
rtx op1 = XEXP (operands[1], 1);
- rtx op0_extend = op0;
- rtx op1_extend = op1;
- /* Record whether operands[2] and operands[3] modes are promoted to word_mode. */
- bool promote_op[2] = {false, false};
+ /* Record whether operands[0] is extended by SImode. */
bool promote_p = false;
machine_mode mode = GET_MODE (operands[0]);
}
}
- if (GET_MODE_SIZE (GET_MODE (op0)) < UNITS_PER_WORD)
- {
- promote_op[0] = (REG_P (op0) && REG_P (operands[2]) &&
- REGNO (op0) == REGNO (operands[2]));
- promote_op[1] = (REG_P (op1) && REG_P (operands[3]) &&
- REGNO (op1) == REGNO (operands[3]));
- }
-
- if (promote_op[0] || promote_op[1])
- {
- mode = word_mode;
- promote_p = true;
- }
-
loongarch_extend_comparands (code, &op0, &op1);
op0 = force_reg (word_mode, op0);
- op0_extend = op0;
- op1_extend = force_reg (word_mode, op1);
+ op1 = CONST_INT_P (op1) ? op1 : force_reg (word_mode, op1);
rtx target = gen_reg_rtx (GET_MODE (op0));
}
}
+ /* If the target of the mov<mode> is SImode, then the two operands are
+ extended to display symbols. */
+ if (TARGET_64BIT && mode == SImode)
+ {
+ loongarch_extend_comparands (code, &operands[2], &operands[3]);
+ operands[2] = force_reg (word_mode, operands[2]);
+ operands[3] = CONST_INT_P (operands[3]) ? operands[3]
+ : force_reg (word_mode, operands[3]);
+
+ promote_p = true;
+ mode = DImode;
+ }
+
rtx cond = gen_rtx_fmt_ee (code, GET_MODE (op0), op0, op1);
/* There is no direct support for general conditional GP move involving
two registers using SEL. */
- if (INTEGRAL_MODE_P (GET_MODE (operands[2]))
- && register_operand (operands[2], VOIDmode)
- && register_operand (operands[3], VOIDmode))
+ if (INTEGRAL_MODE_P (GET_MODE (operands[0])))
{
- rtx op2 = operands[2];
- rtx op3 = operands[3];
+ rtx pdest = promote_p ? gen_reg_rtx (mode) : operands[0];
- if (promote_p)
+ if (register_operand (operands[2], VOIDmode)
+ && register_operand (operands[3], VOIDmode))
{
- if (promote_op[0])
- op2 = op0_extend;
- else
- {
- loongarch_extend_comparands (code, &op2, &const0_rtx);
- op2 = force_reg (mode, op2);
- }
+ rtx sel1 = gen_reg_rtx (mode);
+ rtx sel2 = gen_reg_rtx (mode);
+ emit_insn (gen_rtx_SET (sel1,
+ gen_rtx_IF_THEN_ELSE (mode, cond,
+ operands[2],
+ const0_rtx)));
+ /* Flip the test for the second operand. */
+ cond = gen_rtx_fmt_ee ((code == EQ) ? NE
+ : EQ, GET_MODE (op0),
+ op0, op1);
- if (promote_op[1])
- op3 = op1_extend;
- else
- {
- loongarch_extend_comparands (code, &op3, &const0_rtx);
- op3 = force_reg (mode, op3);
- }
- }
-
- rtx temp = gen_reg_rtx (mode);
- rtx temp2 = gen_reg_rtx (mode);
-
- emit_insn (gen_rtx_SET (temp,
- gen_rtx_IF_THEN_ELSE (mode, cond,
- op2, const0_rtx)));
-
- /* Flip the test for the second operand. */
- cond = gen_rtx_fmt_ee ((code == EQ) ? NE : EQ, GET_MODE (op0), op0, op1);
+ emit_insn (gen_rtx_SET (sel2,
+ gen_rtx_IF_THEN_ELSE (mode, cond,
+ operands[3],
+ const0_rtx)));
- emit_insn (gen_rtx_SET (temp2,
- gen_rtx_IF_THEN_ELSE (mode, cond,
- op3, const0_rtx)));
+ /* Merge the two results, at least one is guaranteed to be zero. */
+ emit_insn (gen_rtx_SET (pdest, gen_rtx_IOR (mode, sel1, sel2)));
+ }
+ else
+ emit_insn (gen_rtx_SET (pdest,
+ gen_rtx_IF_THEN_ELSE (mode, cond,
+ operands[2],
+ operands[3])));
- /* Merge the two results, at least one is guaranteed to be zero. */
if (promote_p)
{
- rtx temp3 = gen_reg_rtx (mode);
- emit_insn (gen_rtx_SET (temp3, gen_rtx_IOR (mode, temp, temp2)));
- temp3 = gen_lowpart (GET_MODE (operands[0]), temp3);
+ pdest = gen_lowpart (GET_MODE (operands[0]), pdest);
/* Nonzero in a subreg if it was made when accessing an object that
was promoted to a wider mode in accord with the PROMOTED_MODE
machine description macro. */
- SUBREG_PROMOTED_VAR_P (temp3) = 1;
+ SUBREG_PROMOTED_VAR_P (pdest) = 1;
/* Sets promoted mode for SUBREG_PROMOTED_VAR_P. */
- SUBREG_PROMOTED_SET (temp3, SRP_SIGNED);
- loongarch_emit_move (operands[0], temp3);
+ SUBREG_PROMOTED_SET (pdest, SRP_SIGNED);
+ loongarch_emit_move (operands[0], pdest);
}
- else
- emit_insn (gen_rtx_SET (operands[0], gen_rtx_IOR (mode, temp, temp2)));
}
else
emit_insn (gen_rtx_SET (operands[0],