aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/config/loongarch/loongarch.cc133
-rw-r--r--gcc/testsuite/gcc.target/loongarch/sign-extend-4.c16
-rw-r--r--gcc/testsuite/gcc.target/loongarch/sign-extend-5.c35
3 files changed, 118 insertions, 66 deletions
diff --git a/gcc/config/loongarch/loongarch.cc b/gcc/config/loongarch/loongarch.cc
index 4a9604e..462743f 100644
--- a/gcc/config/loongarch/loongarch.cc
+++ b/gcc/config/loongarch/loongarch.cc
@@ -5388,6 +5388,26 @@ loongarch_zero_if_equal (rtx cmp0, rtx cmp1)
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
@@ -5417,17 +5437,16 @@ loongarch_extend_comparands (rtx_code code, rtx *op0, rtx *op1)
}
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. */
@@ -5568,11 +5587,8 @@ loongarch_expand_conditional_move (rtx *operands)
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]);
@@ -5675,25 +5691,10 @@ loongarch_expand_conditional_move (rtx *operands)
}
}
- 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));
@@ -5739,65 +5740,65 @@ loongarch_expand_conditional_move (rtx *operands)
}
}
+ /* 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],
diff --git a/gcc/testsuite/gcc.target/loongarch/sign-extend-4.c b/gcc/testsuite/gcc.target/loongarch/sign-extend-4.c
new file mode 100644
index 0000000..d716e5b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/loongarch/sign-extend-4.c
@@ -0,0 +1,16 @@
+/* { dg-do compile } */
+/* { dg-options "-mabi=lp64d -O2" } */
+/* { dg-final { scan-assembler-not "slli.w\t\\\$r\[0-9\]+,\\\$r\[0-9\]+,0" } } */
+
+extern int items;
+extern int gv_fetchmeth (int);
+int
+Perl_gv_fetchmeth (int level)
+{
+ int gv;
+ while (items--)
+ gv = gv_fetchmeth ((level >= 0) ? level + 1 : level - 1);
+
+ return gv;
+}
+
diff --git a/gcc/testsuite/gcc.target/loongarch/sign-extend-5.c b/gcc/testsuite/gcc.target/loongarch/sign-extend-5.c
new file mode 100644
index 0000000..21f5de7
--- /dev/null
+++ b/gcc/testsuite/gcc.target/loongarch/sign-extend-5.c
@@ -0,0 +1,35 @@
+/* { dg-do compile } */
+/* { dg-options "-mabi=lp64d -O2" } */
+/* { dg-final { scan-assembler-not "slli.w" } } */
+
+typedef struct xpvav XPVAV;
+struct xpvav
+{
+ long int xav_fill;
+ long int xav_max;
+};
+typedef struct av AV;
+struct av
+{
+ XPVAV *sv_any;
+ unsigned int sv_refcnt;
+ unsigned int sv_flags;
+};
+void Perl_av_extend (AV *ar, int key);
+void
+Perl_av_unshift (AV *av, int num)
+{
+ int i;
+ int slide;
+
+ if (num)
+ {
+ i = ((XPVAV *)(av)->sv_any)->xav_fill;
+
+ slide = i > 0 ? i : 0;
+ num += slide;
+ Perl_av_extend (av, i + num);
+
+ ((XPVAV *)(av)->sv_any)->xav_max -= slide;
+ }
+}