diff options
author | YunQiang Su <syq@gcc.gnu.org> | 2024-06-08 11:31:19 +0800 |
---|---|---|
committer | YunQiang Su <syq@gcc.gnu.org> | 2024-06-13 09:42:42 +0800 |
commit | e3e5fd0c24c9b82d824da27bf8455bb3654e8eff (patch) | |
tree | 356dcafc728341b7da8035f982ac77806d96becd /gcc | |
parent | 8a5d0d72ea8c324bbfa2cff1284fa8e473fc466d (diff) | |
download | gcc-e3e5fd0c24c9b82d824da27bf8455bb3654e8eff.zip gcc-e3e5fd0c24c9b82d824da27bf8455bb3654e8eff.tar.gz gcc-e3e5fd0c24c9b82d824da27bf8455bb3654e8eff.tar.bz2 |
MIPS: Use signaling fcmp instructions for LT/LE/LTGT
LT/LE: c.lt.fmt/c.le.fmt on pre-R6 and cmp.lt.fmt/cmp.le.fmt have
different semantic:
c.lt.fmt will signal for all NaN, including qNaN;
cmp.lt.fmt will only signal sNaN, while not qNaN;
cmp.slt.fmt has the same semantic as c.lt.fmt;
lt/le of RTL will signaling qNaN.
while in `s<code>_<SCALARF:mode>_using_<FPCC:mode>`, RTL operation
`lt`/`le` are convert to c/cmp's lt/le, which is correct for C.cond.fmt,
while not for CMP.cond.fmt. Let's convert them to slt/sle if ISA_HAS_CCF.
For LTGT, which signals qNaN, `sne` of r6 has same semantic, while pre-R6
has only inverse one `ngl`. Thus for RTL we have to use the `uneq` as the
operator, and introduce a new CC mode: CCEmode to mark it as signaling.
This patch can fix
gcc.dg/torture/pr91323.c for pre-R6;
gcc.dg/torture/builtin-iseqsig-* for R6.
gcc:
* config/mips/mips-modes.def: New CC_MODE CCE.
* config/mips/mips-protos.h(mips_output_compare): New function.
* config/mips/mips.cc(mips_allocate_fcc): Set CCEmode count=1.
(mips_emit_compare): Use CCEmode for LTGT/LT/LE for pre-R6.
(mips_output_compare): New function. Convert lt/le to slt/sle
for R6; convert ueq to ngl for CCEmode.
(mips_hard_regno_mode_ok_uncached): Mention CCEmode.
* config/mips/mips.h: Mention CCEmode for LOAD_EXTEND_OP.
* config/mips/mips.md(FPCC): Add CCE.
(define_mode_iterator MOVECC): Mention CCE.
(define_mode_attr reg): Add CCE with "z".
(define_mode_attr fpcmp): Add CCE with "c".
(define_code_attr fcond): ltgt should use sne instead of ne.
(s<code>_<SCALARF:mode>_using_<FPCC:mode>): call mips_output_compare.
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/config/mips/mips-modes.def | 1 | ||||
-rw-r--r-- | gcc/config/mips/mips-protos.h | 2 | ||||
-rw-r--r-- | gcc/config/mips/mips.cc | 48 | ||||
-rw-r--r-- | gcc/config/mips/mips.h | 2 | ||||
-rw-r--r-- | gcc/config/mips/mips.md | 19 |
5 files changed, 61 insertions, 11 deletions
diff --git a/gcc/config/mips/mips-modes.def b/gcc/config/mips/mips-modes.def index 3235709..21f50a2 100644 --- a/gcc/config/mips/mips-modes.def +++ b/gcc/config/mips/mips-modes.def @@ -54,4 +54,5 @@ ADJUST_ALIGNMENT (CCV4, 16); CC_MODE (CCDSP); /* For floating point conditions in FP registers. */ +CC_MODE (CCE); CC_MODE (CCF); diff --git a/gcc/config/mips/mips-protos.h b/gcc/config/mips/mips-protos.h index 835f421..fcc0a0a 100644 --- a/gcc/config/mips/mips-protos.h +++ b/gcc/config/mips/mips-protos.h @@ -394,4 +394,6 @@ extern bool mips_bit_clear_p (enum machine_mode, unsigned HOST_WIDE_INT); extern void mips_bit_clear_info (enum machine_mode, unsigned HOST_WIDE_INT, int *, int *); +extern const char *mips_output_compare (const char *fpcmp, const char *fcond, + const char *fmt, const char *fpcc_mode, bool swap); #endif /* ! GCC_MIPS_PROTOS_H */ diff --git a/gcc/config/mips/mips.cc b/gcc/config/mips/mips.cc index 278d944..b7acf04 100644 --- a/gcc/config/mips/mips.cc +++ b/gcc/config/mips/mips.cc @@ -5659,7 +5659,7 @@ mips_allocate_fcc (machine_mode mode) gcc_assert (TARGET_HARD_FLOAT && ISA_HAS_8CC); - if (mode == CCmode) + if (mode == CCmode || mode == CCEmode) count = 1; else if (mode == CCV2mode) count = 2; @@ -5788,17 +5788,57 @@ mips_emit_compare (enum rtx_code *code, rtx *op0, rtx *op1, bool need_eq_ne_p) /* Three FP conditions cannot be implemented by reversing the operands for C.cond.fmt, instead a reversed condition code is required and a test for false. */ + machine_mode ccmode = CCmode; + switch (*code) + { + case LTGT: + case LT: + case LE: + ccmode = CCEmode; + break; + default: + break; + } *code = mips_reversed_fp_cond (&cmp_code) ? EQ : NE; if (ISA_HAS_8CC) - *op0 = mips_allocate_fcc (CCmode); + *op0 = mips_allocate_fcc (ccmode); else - *op0 = gen_rtx_REG (CCmode, FPSW_REGNUM); + *op0 = gen_rtx_REG (ccmode, FPSW_REGNUM); } *op1 = const0_rtx; mips_emit_binary (cmp_code, *op0, cmp_op0, cmp_op1); } } + + +const char * +mips_output_compare (const char *fpcmp, const char *fcond, + const char *fmt, const char *fpcc_mode, bool swap) +{ + const char *fc = fcond; + + if (ISA_HAS_CCF) + { + /* c.lt.fmt is signaling, while cmp.lt.fmt is quiet. */ + if (strcmp (fcond, "lt") == 0) + fc = "slt"; + else if (strcmp (fcond, "le") == 0) + fc = "sle"; + } + else if (strcmp (fpcc_mode, "cce") == 0) + { + /* It was LTGT, while we have only inverse one. It was then converted + to UNEQ by mips_reversed_fp_cond, and we used CCEmode to mark it. + Lets convert it back to ngl now. */ + if (strcmp (fcond, "ueq") == 0) + fc = "ngl"; + } + if (swap) + return concat(fpcmp, ".", fc, ".", fmt, "\t%Z0%2,%1", NULL); + return concat(fpcmp, ".", fc, ".", fmt, "\t%Z0%1,%2", NULL); +} + /* Try performing the comparison in OPERANDS[1], whose arms are OPERANDS[2] and OPERAND[3]. Store the result in OPERANDS[0]. @@ -13142,7 +13182,7 @@ mips_hard_regno_mode_ok_uncached (unsigned int regno, machine_mode mode) && ST_REG_P (regno) && (regno - ST_REG_FIRST) % 4 == 0); - if (mode == CCmode) + if (mode == CCmode || mode == CCEmode) return ISA_HAS_8CC ? ST_REG_P (regno) : regno == FPSW_REGNUM; size = GET_MODE_SIZE (mode); diff --git a/gcc/config/mips/mips.h b/gcc/config/mips/mips.h index 9d96596..d18ca7d 100644 --- a/gcc/config/mips/mips.h +++ b/gcc/config/mips/mips.h @@ -1771,7 +1771,7 @@ FP_ASM_SPEC "\ /* When in 64-bit mode, move insns will sign extend SImode and CCmode moves. All other references are zero extended. */ #define LOAD_EXTEND_OP(MODE) \ - (TARGET_64BIT && ((MODE) == SImode || (MODE) == CCmode) \ + (TARGET_64BIT && ((MODE) == SImode || (MODE) == CCmode || (MODE) == CCEmode) \ ? SIGN_EXTEND : ZERO_EXTEND) /* Define this macro if it is advisable to hold scalars in registers diff --git a/gcc/config/mips/mips.md b/gcc/config/mips/mips.md index 7de8512..806fd29c 100644 --- a/gcc/config/mips/mips.md +++ b/gcc/config/mips/mips.md @@ -832,11 +832,14 @@ (define_mode_iterator MOVECC [SI (DI "TARGET_64BIT") (CC "TARGET_HARD_FLOAT && !TARGET_LOONGSON_2EF + && !TARGET_MIPS5900") + (CCE "TARGET_HARD_FLOAT + && !TARGET_LOONGSON_2EF && !TARGET_MIPS5900")]) ;; This mode iterator allows :FPCC to be used anywhere that an FP condition ;; is needed. -(define_mode_iterator FPCC [(CC "!ISA_HAS_CCF") +(define_mode_iterator FPCC [(CC "!ISA_HAS_CCF") (CCE "!ISA_HAS_CCF") (CCF "ISA_HAS_CCF")]) ;; 32-bit integer moves for which we provide move patterns. @@ -928,7 +931,7 @@ ;; This attribute gives the best constraint to use for registers of ;; a given mode. -(define_mode_attr reg [(SI "d") (DI "d") (CC "z") (CCF "f")]) +(define_mode_attr reg [(SI "d") (DI "d") (CC "z") (CCE "z") (CCF "f")]) ;; This attribute gives the format suffix for floating-point operations. (define_mode_attr fmt [(SF "s") (DF "d") (V2SF "ps")]) @@ -976,7 +979,7 @@ [(SF "!ISA_MIPS1") (DF "!ISA_MIPS1") (V2SF "TARGET_SB1")]) ;; This attribute provides the correct mnemonic for each FP condition mode. -(define_mode_attr fpcmp [(CC "c") (CCF "cmp")]) +(define_mode_attr fpcmp [(CC "c") (CCE "c") (CCF "cmp")]) ;; This code iterator allows signed and unsigned widening multiplications ;; to use the same template. @@ -1082,7 +1085,7 @@ (lt "lt") (le "le") (ordered "or") - (ltgt "ne") + (ltgt "sne") (ne "une")]) ;; Similar, but for swapped conditions. @@ -6410,7 +6413,9 @@ (fcond:FPCC (match_operand:SCALARF 1 "register_operand" "f") (match_operand:SCALARF 2 "register_operand" "f")))] "" - "<fpcmp>.<fcond>.<fmt>\t%Z0%1,%2" + { + return mips_output_compare ("<fpcmp>", "<fcond>", "<fmt>", "<FPCC:mode>", false); + } [(set_attr "type" "fcmp") (set_attr "mode" "FPSW")]) @@ -6419,7 +6424,9 @@ (swapped_fcond:FPCC (match_operand:SCALARF 1 "register_operand" "f") (match_operand:SCALARF 2 "register_operand" "f")))] "" - "<fpcmp>.<swapped_fcond>.<fmt>\t%Z0%2,%1" + { + return mips_output_compare ("<fpcmp>", "<swapped_fcond>", "<fmt>", "<FPCC:mode>", true); + } [(set_attr "type" "fcmp") (set_attr "mode" "FPSW")]) |