aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorYunQiang Su <syq@gcc.gnu.org>2024-06-08 11:31:19 +0800
committerYunQiang Su <syq@gcc.gnu.org>2024-06-13 09:42:42 +0800
commite3e5fd0c24c9b82d824da27bf8455bb3654e8eff (patch)
tree356dcafc728341b7da8035f982ac77806d96becd /gcc
parent8a5d0d72ea8c324bbfa2cff1284fa8e473fc466d (diff)
downloadgcc-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.def1
-rw-r--r--gcc/config/mips/mips-protos.h2
-rw-r--r--gcc/config/mips/mips.cc48
-rw-r--r--gcc/config/mips/mips.h2
-rw-r--r--gcc/config/mips/mips.md19
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")])