diff mbox series

[v2] MIPS: Use signaling fcmp instructions for LT/LE/LTGT

Message ID 20240608232808.47532-1-syq@gcc.gnu.org
State New
Headers show
Series [v2] MIPS: Use signaling fcmp instructions for LT/LE/LTGT | expand

Commit Message

YunQiang Su June 8, 2024, 11:28 p.m. UTC
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.
---
 gcc/config/mips/mips-modes.def |  1 +
 gcc/config/mips/mips-protos.h  |  2 ++
 gcc/config/mips/mips.cc        | 48 +++++++++++++++++++++++++++++++---
 gcc/config/mips/mips.h         |  2 +-
 gcc/config/mips/mips.md        | 19 +++++++++-----
 5 files changed, 61 insertions(+), 11 deletions(-)
diff mbox series

Patch

diff --git a/gcc/config/mips/mips-modes.def b/gcc/config/mips/mips-modes.def
index 323570928fc..21f50a22546 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 835f42128b9..fcc0a0ae663 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 278d9446482..b7acf041903 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 9d965966f2f..d18ca7dad8a 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 7de85123e7c..806fd29cf97 100644
--- a/gcc/config/mips/mips.md
+++ b/gcc/config/mips/mips.md
@@ -831,12 +831,15 @@  (define_mode_iterator P [(SI "Pmode == SImode") (DI "Pmode == DImode")])
 ;; conditional-move-type condition is needed.
 (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 @@  (define_mode_attr si8_di5 [(SI "8") (DI "5")])
 
 ;; 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 @@  (define_mode_attr sqrt_condition
   [(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 @@  (define_code_attr fcond [(unordered "un")
 			 (lt "lt")
 			 (le "le")
 			 (ordered "or")
-			 (ltgt "ne")
+			 (ltgt "sne")
 			 (ne "une")])
 
 ;; Similar, but for swapped conditions.
@@ -6410,7 +6413,9 @@  (define_insn "s<code>_<SCALARF:mode>_using_<FPCC:mode>"
 	(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 @@  (define_insn "s<code>_<SCALARF:mode>_using_<FPCC:mode>"
 	(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")])