diff options
| -rw-r--r-- | gcc/config/loongarch/loongarch.cc | 133 | ||||
| -rw-r--r-- | gcc/testsuite/gcc.target/loongarch/sign-extend-4.c | 16 | ||||
| -rw-r--r-- | gcc/testsuite/gcc.target/loongarch/sign-extend-5.c | 35 |
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; + } +} |
