diff mbox series

MIPS: Add some floating point instructions support for MIPSr6

Message ID 20240726063626.33588-1-jie.mei@oss.cipunited.com
State New
Headers show
Series MIPS: Add some floating point instructions support for MIPSr6 | expand

Commit Message

Jie Mei July 26, 2024, 6:36 a.m. UTC
This patch adds some floating point instructiions from mips32r6,
for instance, MINA/MAXA.fmt, RINT.fmt, CLASS.fmt etc.

Also add built-in functions to MIPSr6 to better handle tests
for MIPSr6.

gcc/ChangeLog:

	* config/mips/i6400.md (i6400_fpu_minmax): Include
	fclass type.
	(i6400_fpu_fadd): Include frint type.
	* config/mips/mips.cc (AVAIL_NON_MIPS16): Add an entry
	for __builtin_mipsr6_xxx.
	(MIPSR6_BUILTIN_PURE): Same as above.
	(CODE_FOR_mipsr6_min_a_s, CODE_FOR_mipsr6_min_a_d)
	(CODE_FOR_mipsr6_max_a_s, CODE_FOR_mipsr6_max_a_d)
	(CODE_FOR_mipsr6_rint_s, CODE_FOR_mipsr6_rint_d)
	(CODE_FOR_mipsr6_class_s, CODE_FOR_mipsr6_class_d):
	New code_aliasing macros.
	(mips_builtins): Add mips32r6 min_a_s, min_a_d, max_a_s,
	max_a_d, rint_s, rint_d, class_s, class_d builtins.
	* config/mips/mips.h (ISA_HAS_FRINT): Define a new macro.
	(ISA_HAS_FCLASS): Same as above.
	* config/mips/mips.md (UNSPEC_FRINT): New unspec.
	(UNSPEC_FCLASS): Same as above.
	(type): Add frint and fclass.
	(fmin_a_<mode>): Generates MINA.fmt instructions.
	(fmax_a_<mode>): Generates MAXA.fmt instructions.
	(frint_<mode>): Generates RINT.fmt instructions.
	(fclass_<mode>): Generates CLASS.fmt instructions.
	* config/mips/p6600.md (p6600_fpu_fadd): Include
	frint type.
	(p6600_fpu_fabs): Incled fclass type.

gcc/testsuite/ChangeLog:

	* gcc.target/mips/mips-class.c: New tests for MIPSr6
	* gcc.target/mips/mips-minamaxa.c: Same as above.
	* gcc.target/mips/mips-rint.c: Same as above.
---
 gcc/config/mips/i6400.md                      |  8 +--
 gcc/config/mips/mips.cc                       | 28 ++++++++++
 gcc/config/mips/mips.h                        |  4 ++
 gcc/config/mips/mips.md                       | 52 ++++++++++++++++++-
 gcc/config/mips/p6600.md                      |  8 +--
 gcc/testsuite/gcc.target/mips/mips-class.c    | 17 ++++++
 gcc/testsuite/gcc.target/mips/mips-minamaxa.c | 31 +++++++++++
 gcc/testsuite/gcc.target/mips/mips-rint.c     | 17 ++++++
 8 files changed, 155 insertions(+), 10 deletions(-)
 create mode 100644 gcc/testsuite/gcc.target/mips/mips-class.c
 create mode 100644 gcc/testsuite/gcc.target/mips/mips-minamaxa.c
 create mode 100644 gcc/testsuite/gcc.target/mips/mips-rint.c

Comments

YunQiang Su Sept. 3, 2024, 12:30 a.m. UTC | #1
Jie Mei <jie.mei@oss.cipunited.com> 于2024年7月26日周五 14:50写道:
>
> This patch adds some floating point instructiions from mips32r6,
> for instance, MINA/MAXA.fmt, RINT.fmt, CLASS.fmt etc.
>
> Also add built-in functions to MIPSr6 to better handle tests
> for MIPSr6.
>
> gcc/ChangeLog:
>
>         * config/mips/i6400.md (i6400_fpu_minmax): Include
>         fclass type.
>         (i6400_fpu_fadd): Include frint type.
>         * config/mips/mips.cc (AVAIL_NON_MIPS16): Add an entry
>         for __builtin_mipsr6_xxx.

Since libc has fmaxmag/fminmag, maybe we should use __builtin_fmaxmag.
And `rint/rintf` exist in libc.


>         (MIPSR6_BUILTIN_PURE): Same as above.
>         (CODE_FOR_mipsr6_min_a_s, CODE_FOR_mipsr6_min_a_d)
>         (CODE_FOR_mipsr6_max_a_s, CODE_FOR_mipsr6_max_a_d)
>         (CODE_FOR_mipsr6_rint_s, CODE_FOR_mipsr6_rint_d)
>         (CODE_FOR_mipsr6_class_s, CODE_FOR_mipsr6_class_d):
>         New code_aliasing macros.
>         (mips_builtins): Add mips32r6 min_a_s, min_a_d, max_a_s,
>         max_a_d, rint_s, rint_d, class_s, class_d builtins.
>         * config/mips/mips.h (ISA_HAS_FRINT): Define a new macro.
>         (ISA_HAS_FCLASS): Same as above.
>         * config/mips/mips.md (UNSPEC_FRINT): New unspec.
>         (UNSPEC_FCLASS): Same as above.
>         (type): Add frint and fclass.
>         (fmin_a_<mode>): Generates MINA.fmt instructions.
>         (fmax_a_<mode>): Generates MAXA.fmt instructions.
>         (frint_<mode>): Generates RINT.fmt instructions.
>         (fclass_<mode>): Generates CLASS.fmt instructions.
>         * config/mips/p6600.md (p6600_fpu_fadd): Include
>         frint type.
>         (p6600_fpu_fabs): Incled fclass type.
>
> gcc/testsuite/ChangeLog:
>
>         * gcc.target/mips/mips-class.c: New tests for MIPSr6
>         * gcc.target/mips/mips-minamaxa.c: Same as above.
>         * gcc.target/mips/mips-rint.c: Same as above.
> ---
>  gcc/config/mips/i6400.md                      |  8 +--
>  gcc/config/mips/mips.cc                       | 28 ++++++++++
>  gcc/config/mips/mips.h                        |  4 ++
>  gcc/config/mips/mips.md                       | 52 ++++++++++++++++++-
>  gcc/config/mips/p6600.md                      |  8 +--
>  gcc/testsuite/gcc.target/mips/mips-class.c    | 17 ++++++
>  gcc/testsuite/gcc.target/mips/mips-minamaxa.c | 31 +++++++++++
>  gcc/testsuite/gcc.target/mips/mips-rint.c     | 17 ++++++
>  8 files changed, 155 insertions(+), 10 deletions(-)
>  create mode 100644 gcc/testsuite/gcc.target/mips/mips-class.c
>  create mode 100644 gcc/testsuite/gcc.target/mips/mips-minamaxa.c
>  create mode 100644 gcc/testsuite/gcc.target/mips/mips-rint.c
>
> diff --git a/gcc/config/mips/i6400.md b/gcc/config/mips/i6400.md
> index d6f691ee217..48ce980e1c2 100644
> --- a/gcc/config/mips/i6400.md
> +++ b/gcc/config/mips/i6400.md
> @@ -219,16 +219,16 @@
>         (eq_attr "type" "fabs,fneg,fmove"))
>    "i6400_fpu_short, i6400_fpu_apu")
>
> -;; min, max
> +;; min, max, fclass
>  (define_insn_reservation "i6400_fpu_minmax" 2
>    (and (eq_attr "cpu" "i6400")
> -       (eq_attr "type" "fminmax"))
> +       (eq_attr "type" "fminmax,fclass"))
>    "i6400_fpu_short+i6400_fpu_logic")
>
> -;; fadd, fsub, fcvt
> +;; fadd, fsub, fcvt, frint
>  (define_insn_reservation "i6400_fpu_fadd" 4
>    (and (eq_attr "cpu" "i6400")
> -       (eq_attr "type" "fadd,fcvt"))
> +       (eq_attr "type" "fadd,fcvt,frint"))
>    "i6400_fpu_long, i6400_fpu_apu")
>
>  ;; fmul
> diff --git a/gcc/config/mips/mips.cc b/gcc/config/mips/mips.cc
> index 6c797b62164..14a1f23eb70 100644
> --- a/gcc/config/mips/mips.cc
> +++ b/gcc/config/mips/mips.cc
> @@ -15775,6 +15775,7 @@ AVAIL_NON_MIPS16 (dspr2_32, !TARGET_64BIT && TARGET_DSPR2)
>  AVAIL_NON_MIPS16 (loongson, TARGET_LOONGSON_MMI)
>  AVAIL_MIPS16E2_OR_NON_MIPS16 (cache, TARGET_CACHE_BUILTIN)
>  AVAIL_NON_MIPS16 (msa, TARGET_MSA)
> +AVAIL_NON_MIPS16 (r6, mips_isa_rev >= 6)
>
>  /* Construct a mips_builtin_description from the given arguments.
>
> @@ -15940,6 +15941,14 @@ AVAIL_NON_MIPS16 (msa, TARGET_MSA)
>      "__builtin_msa_" #INSN,  MIPS_BUILTIN_DIRECT_NO_TARGET,            \
>      FUNCTION_TYPE, mips_builtin_avail_msa, false }
>
> +/* Define a MIPSr6 MIPS_BUILTIN_DIRECT pure function __builtin_mipsr6_<INSN>
> +   for instruction CODE_FOR_mipsr6_<INSN>.  FUNCTION_TYPE is a builtin_description
> +   field.  */
> +#define MIPSR6_BUILTIN_PURE(INSN, FUNCTION_TYPE)                       \
> +    { CODE_FOR_mipsr6_ ## INSN, MIPS_FP_COND_f,                                \
> +    "__builtin_mipsr6_" #INSN,  MIPS_BUILTIN_DIRECT,                   \
> +    FUNCTION_TYPE, mips_builtin_avail_r6, true }
> +
>  #define CODE_FOR_mips_sqrt_ps CODE_FOR_sqrtv2sf2
>  #define CODE_FOR_mips_addq_ph CODE_FOR_addv2hi3
>  #define CODE_FOR_mips_addu_qb CODE_FOR_addv4qi3
> @@ -16177,6 +16186,15 @@ AVAIL_NON_MIPS16 (msa, TARGET_MSA)
>  #define CODE_FOR_msa_ldi_w CODE_FOR_msa_ldiv4si
>  #define CODE_FOR_msa_ldi_d CODE_FOR_msa_ldiv2di
>
> +#define CODE_FOR_mipsr6_min_a_s CODE_FOR_fmin_a_sf
> +#define CODE_FOR_mipsr6_min_a_d CODE_FOR_fmin_a_df
> +#define CODE_FOR_mipsr6_max_a_s CODE_FOR_fmax_a_sf
> +#define CODE_FOR_mipsr6_max_a_d CODE_FOR_fmax_a_df
> +#define CODE_FOR_mipsr6_rint_s CODE_FOR_frint_sf
> +#define CODE_FOR_mipsr6_rint_d CODE_FOR_frint_df
> +#define CODE_FOR_mipsr6_class_s CODE_FOR_fclass_sf
> +#define CODE_FOR_mipsr6_class_d CODE_FOR_fclass_df
> +
>  static const struct mips_builtin_description mips_builtins[] = {
>  #define MIPS_GET_FCSR 0
>    DIRECT_BUILTIN (get_fcsr, MIPS_USI_FTYPE_VOID, hard_float),
> @@ -16998,6 +17016,16 @@ static const struct mips_builtin_description mips_builtins[] = {
>    MSA_NO_TARGET_BUILTIN (ctcmsa, MIPS_VOID_FTYPE_UQI_SI),
>    MSA_BUILTIN_PURE (cfcmsa, MIPS_SI_FTYPE_UQI),
>    MSA_BUILTIN_PURE (move_v, MIPS_V16QI_FTYPE_V16QI),
> +
> +  /* Built-in functions for MIPSr6.  */
> +  MIPSR6_BUILTIN_PURE (min_a_s, MIPS_SF_FTYPE_SF_SF),
> +  MIPSR6_BUILTIN_PURE (min_a_d, MIPS_DF_FTYPE_DF_DF),
> +  MIPSR6_BUILTIN_PURE (max_a_s, MIPS_SF_FTYPE_SF_SF),
> +  MIPSR6_BUILTIN_PURE (max_a_d, MIPS_DF_FTYPE_DF_DF),
> +  MIPSR6_BUILTIN_PURE (rint_s, MIPS_SF_FTYPE_SF),
> +  MIPSR6_BUILTIN_PURE (rint_d, MIPS_DF_FTYPE_DF),
> +  MIPSR6_BUILTIN_PURE (class_s, MIPS_SF_FTYPE_SF),
> +  MIPSR6_BUILTIN_PURE (class_d, MIPS_DF_FTYPE_DF),
>  };
>
>  /* Index I is the function declaration for mips_builtins[I], or null if the
> diff --git a/gcc/config/mips/mips.h b/gcc/config/mips/mips.h
> index 84dd64d98a0..b4bb99e19b1 100644
> --- a/gcc/config/mips/mips.h
> +++ b/gcc/config/mips/mips.h
> @@ -1264,6 +1264,10 @@ struct mips_cpu_info {
>
>  #define ISA_HAS_FMIN_FMAX      (mips_isa_rev >= 6)
>
> +#define ISA_HAS_FRINT          (mips_isa_rev >= 6)
> +
> +#define ISA_HAS_FCLASS         (mips_isa_rev >= 6)
> +
>  /* ISA has data indexed prefetch instructions.  This controls use of
>     'prefx', along with TARGET_HARD_FLOAT and TARGET_DOUBLE_FLOAT.
>     (prefx is a cop1x instruction, so can only be used if FP is
> diff --git a/gcc/config/mips/mips.md b/gcc/config/mips/mips.md
> index 737d2566ec8..297c5141b1f 100644
> --- a/gcc/config/mips/mips.md
> +++ b/gcc/config/mips/mips.md
> @@ -100,6 +100,8 @@
>    ;; Floating-point unspecs.
>    UNSPEC_FMIN
>    UNSPEC_FMAX
> +  UNSPEC_FRINT
> +  UNSPEC_FCLASS
>
>    ;; HI/LO moves.
>    UNSPEC_MFHI
> @@ -375,6 +377,8 @@
>  ;; frsqrt1      floating point reciprocal square root step1
>  ;; frsqrt2      floating point reciprocal square root step2
>  ;; fminmax      floating point min/max
> +;; frint        floating point round to integral
> +;; fclass       floating point class mask
>  ;; dspmac       DSP MAC instructions not saturating the accumulator
>  ;; dspmacsat    DSP MAC instructions that saturate the accumulator
>  ;; accext       DSP accumulator extract instructions
> @@ -392,8 +396,8 @@
>     prefetch,prefetchx,condmove,mtc,mfc,mthi,mtlo,mfhi,mflo,const,arith,logical,
>     shift,slt,signext,clz,pop,trap,imul,imul3,imul3nc,imadd,idiv,idiv3,move,
>     fmove,fadd,fmul,fmadd,fdiv,frdiv,frdiv1,frdiv2,fabs,fneg,fcmp,fcvt,fsqrt,
> -   frsqrt,frsqrt1,frsqrt2,fminmax,dspmac,dspmacsat,accext,accmod,dspalu,
> -   dspalusat,multi,atomic,syncloop,nop,ghost,multimem,
> +   frsqrt,frsqrt1,frsqrt2,fminmax,frint,fclass,dspmac,dspmacsat,accext,
> +   accmod,dspalu,dspalusat,multi,atomic,syncloop,nop,ghost,multimem,
>     simd_div,simd_fclass,simd_flog2,simd_fadd,simd_fcvt,simd_fmul,simd_fmadd,
>     simd_fdiv,simd_bitins,simd_bitmov,simd_insert,simd_sld,simd_mul,simd_fcmp,
>     simd_fexp2,simd_int_arith,simd_bit,simd_shift,simd_splat,simd_fill,
> @@ -8007,6 +8011,50 @@
>    [(set_attr "type" "fminmax")
>    (set_attr "mode" "<UNITMODE>")])
>
> +(define_insn "fmin_a_<mode>"
> +  [(set (match_operand:SCALARF 0 "register_operand" "=f")
> +    (if_then_else
> +       (lt (abs:SCALARF (match_operand:SCALARF 1 "register_operand" "f"))
> +           (abs:SCALARF (match_operand:SCALARF 2 "register_operand" "f")))
> +       (match_dup 1)
> +       (match_dup 2)))]
> +  "ISA_HAS_FMIN_FMAX"
> +  "mina.<fmt>\t%0,%1,%2"
> +  [(set_attr "type" "fminmax")
> +   (set_attr "mode" "<UNITMODE>")])
> +
> +(define_insn "fmax_a_<mode>"
> +  [(set (match_operand:SCALARF 0 "register_operand" "=f")
> +    (if_then_else
> +       (gt (abs:SCALARF (match_operand:SCALARF 1 "register_operand" "f"))
> +           (abs:SCALARF (match_operand:SCALARF 2 "register_operand" "f")))
> +       (match_dup 1)
> +       (match_dup 2)))]
> +  "ISA_HAS_FMIN_FMAX"
> +  "maxa.<fmt>\t%0,%1,%2"
> +  [(set_attr "type" "fminmax")
> +   (set_attr "mode" "<UNITMODE>")])
> +
> +;;Float point round to integral
> +(define_insn "frint_<mode>"
> +  [(set (match_operand:SCALARF 0 "register_operand" "=f")
> +       (unspec:SCALARF [(match_operand:SCALARF 1 "register_operand" "f")]
> +                       UNSPEC_FRINT))]
> +  "ISA_HAS_FRINT"
> +  "rint.<fmt>\t%0,%1"
> +  [(set_attr "type" "frint")
> +   (set_attr "mode" "<UNITMODE>")])
> +
> +;;Float point class mask
> +(define_insn "fclass_<mode>"
> +  [(set (match_operand:SCALARF 0 "register_operand" "=f")
> +       (unspec:SCALARF [(match_operand:SCALARF 1 "register_operand" "f")]
> +                       UNSPEC_FCLASS))]
> +  "ISA_HAS_FCLASS"
> +  "class.<fmt>\t%0,%1"
> +  [(set_attr "type" "fclass")
> +   (set_attr "mode" "<UNITMODE>")])
> +
>  ;; 2 HI loads are joined.
>  (define_peephole2
>    [(set (match_operand:SI 0 "register_operand")
> diff --git a/gcc/config/mips/p6600.md b/gcc/config/mips/p6600.md
> index b6cb554939a..d541e98fdec 100644
> --- a/gcc/config/mips/p6600.md
> +++ b/gcc/config/mips/p6600.md
> @@ -161,16 +161,16 @@
>  ;; FPU pipe
>  ;;
>
> -;; fadd, fsub
> +;; fadd, fsub, frint
>  (define_insn_reservation "p6600_fpu_fadd" 4
>    (and (eq_attr "cpu" "p6600")
> -       (eq_attr "type" "fadd"))
> +       (eq_attr "type" "fadd,frint"))
>    "p6600_fpu_long, p6600_fpu_apu")
>
> -;; fabs, fneg, fcmp, fminmax
> +;; fabs, fneg, fcmp, fminmax, fclass
>  (define_insn_reservation "p6600_fpu_fabs" 2
>    (and (eq_attr "cpu" "p6600")
> -       (ior (eq_attr "type" "fabs,fneg,fcmp,fmove,fminmax")
> +       (ior (eq_attr "type" "fabs,fneg,fcmp,fmove,fminmax,fclass")
>            (and (eq_attr "type" "condmove")
>                 (eq_attr "mode" "SF,DF"))))
>    "p6600_fpu_short, p6600_fpu_apu")
> diff --git a/gcc/testsuite/gcc.target/mips/mips-class.c b/gcc/testsuite/gcc.target/mips/mips-class.c
> new file mode 100644
> index 00000000000..e71a853fb8c
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/mips/mips-class.c
> @@ -0,0 +1,17 @@
> +/* { dg-do compile } */
> +/* { dg-options "-mhard-float -march=mips32r6" } */
> +
> +NOMIPS16 float
> +test01 (float a)
> +{
> +  return __builtin_mipsr6_class_s (a);
> +}
> +
> +NOMIPS16 double
> +test02 (double a)
> +{
> +  return __builtin_mipsr6_class_d (a);
> +}
> +
> +/* { dg-final { scan-assembler "class\\.s" } } */
> +/* { dg-final { scan-assembler "class\\.d" } } */
> diff --git a/gcc/testsuite/gcc.target/mips/mips-minamaxa.c b/gcc/testsuite/gcc.target/mips/mips-minamaxa.c
> new file mode 100644
> index 00000000000..d41d6078779
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/mips/mips-minamaxa.c
> @@ -0,0 +1,31 @@
> +/* { dg-do compile } */
> +/* { dg-options "-mhard-float -march=mips32r6" } */
> +
> +NOMIPS16 float
> +test01 (float a, float b)
> +{
> +  return __builtin_mipsr6_min_a_s (a, b);
> +}
> +
> +NOMIPS16 double
> +test02 (double a, double b)
> +{
> +  return __builtin_mipsr6_min_a_d (a, b);
> +}
> +
> +NOMIPS16 float
> +test03 (float a, float b)
> +{
> +  return __builtin_mipsr6_max_a_s (a, b);
> +}
> +
> +NOMIPS16 double
> +test04 (double a, double b)
> +{
> +  return __builtin_mipsr6_max_a_d (a, b);
> +}
> +
> +/* { dg-final { scan-assembler "mina\\.s" } } */
> +/* { dg-final { scan-assembler "mina\\.d" } } */
> +/* { dg-final { scan-assembler "maxa\\.s" } } */
> +/* { dg-final { scan-assembler "maxa\\.d" } } */
> diff --git a/gcc/testsuite/gcc.target/mips/mips-rint.c b/gcc/testsuite/gcc.target/mips/mips-rint.c
> new file mode 100644
> index 00000000000..a964b8c4267
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/mips/mips-rint.c
> @@ -0,0 +1,17 @@
> +/* { dg-do compile } */
> +/* { dg-options "-mhard-float -march=mips32r6" } */
> +
> +NOMIPS16 float
> +test01 (float a)
> +{
> +  return __builtin_mipsr6_rint_s (a);
> +}
> +
> +NOMIPS16 double
> +test02 (double a)
> +{
> +  return __builtin_mipsr6_rint_d (a);
> +}
> +
> +/* { dg-final { scan-assembler "rint\\.s" } } */
> +/* { dg-final { scan-assembler "rint\\.d" } } */
> --
> 2.41.0
Jie Mei Sept. 10, 2024, 8:50 a.m. UTC | #2
在 2024/9/3 08:30, YunQiang Su 写道:
> Jie Mei <jie.mei@oss.cipunited.com> 于2024年7月26日周五 14:50写道:
>>
>> This patch adds some floating point instructiions from mips32r6,
>> for instance, MINA/MAXA.fmt, RINT.fmt, CLASS.fmt etc.
>>
>> Also add built-in functions to MIPSr6 to better handle tests
>> for MIPSr6.
>>
>> gcc/ChangeLog:
>>
>>         * config/mips/i6400.md (i6400_fpu_minmax): Include
>>         fclass type.
>>         (i6400_fpu_fadd): Include frint type.
>>         * config/mips/mips.cc (AVAIL_NON_MIPS16): Add an entry
>>         for __builtin_mipsr6_xxx.
> 
> Since libc has fmaxmag/fminmag, maybe we should use __builtin_fmaxmag.
> And `rint/rintf` exist in libc.
> 
> 

There is no such built-in function `__builtin_fmaxmag` in gcc, as the 
only file that mentioned `fmaxmag/fminmag` in the code tree 
`fortan/trans-intrinsic.cc` stated:

> IEEE_MIN_NUM_MAG and IEEE_MAX_NUM_MAG translate to C 
> fminmag() and fmaxmag(), which do not exist as built-ins.

As for the function `__builtin_rint`, although it exists, however, after 
defining the instruction in `mips.md`, GCC still won't generate `RINT.fmt` 
instruction for MIPS, it generates following code instead:

>	lui     $28,%hi(__gnu_local_gp)
>	addiu   $28,$28,%lo(__gnu_local_gp)
>	lw      $25,%call16(rint)($28)
>	.reloc  1f,R_MIPS_JALR,rint

This patch tries to fix said problem with an extra built-in function
like the MSA solution for `FRINT.fmt`.

>>         (MIPSR6_BUILTIN_PURE): Same as above.
>>         (CODE_FOR_mipsr6_min_a_s, CODE_FOR_mipsr6_min_a_d)
>>         (CODE_FOR_mipsr6_max_a_s, CODE_FOR_mipsr6_max_a_d)
>>         (CODE_FOR_mipsr6_rint_s, CODE_FOR_mipsr6_rint_d)
>>         (CODE_FOR_mipsr6_class_s, CODE_FOR_mipsr6_class_d):
>>         New code_aliasing macros.
>>         (mips_builtins): Add mips32r6 min_a_s, min_a_d, max_a_s,
>>         max_a_d, rint_s, rint_d, class_s, class_d builtins.
>>         * config/mips/mips.h (ISA_HAS_FRINT): Define a new macro.
>>         (ISA_HAS_FCLASS): Same as above.
>>         * config/mips/mips.md (UNSPEC_FRINT): New unspec.
>>         (UNSPEC_FCLASS): Same as above.
>>         (type): Add frint and fclass.
>>         (fmin_a_<mode>): Generates MINA.fmt instructions.
>>         (fmax_a_<mode>): Generates MAXA.fmt instructions.
>>         (frint_<mode>): Generates RINT.fmt instructions.
>>         (fclass_<mode>): Generates CLASS.fmt instructions.
>>         * config/mips/p6600.md (p6600_fpu_fadd): Include
>>         frint type.
>>         (p6600_fpu_fabs): Incled fclass type.
>>
>> gcc/testsuite/ChangeLog:
>>
>>         * gcc.target/mips/mips-class.c: New tests for MIPSr6
>>         * gcc.target/mips/mips-minamaxa.c: Same as above.
>>         * gcc.target/mips/mips-rint.c: Same as above.
>> ---
>>  gcc/config/mips/i6400.md                      |  8 +--
>>  gcc/config/mips/mips.cc                       | 28 ++++++++++
>>  gcc/config/mips/mips.h                        |  4 ++
>>  gcc/config/mips/mips.md                       | 52 ++++++++++++++++++-
>>  gcc/config/mips/p6600.md                      |  8 +--
>>  gcc/testsuite/gcc.target/mips/mips-class.c    | 17 ++++++
>>  gcc/testsuite/gcc.target/mips/mips-minamaxa.c | 31 +++++++++++
>>  gcc/testsuite/gcc.target/mips/mips-rint.c     | 17 ++++++
>>  8 files changed, 155 insertions(+), 10 deletions(-)
>>  create mode 100644 gcc/testsuite/gcc.target/mips/mips-class.c
>>  create mode 100644 gcc/testsuite/gcc.target/mips/mips-minamaxa.c
>>  create mode 100644 gcc/testsuite/gcc.target/mips/mips-rint.c
>>
>> diff --git a/gcc/config/mips/i6400.md b/gcc/config/mips/i6400.md
>> index d6f691ee217..48ce980e1c2 100644
>> --- a/gcc/config/mips/i6400.md
>> +++ b/gcc/config/mips/i6400.md
>> @@ -219,16 +219,16 @@
>>         (eq_attr "type" "fabs,fneg,fmove"))
>>    "i6400_fpu_short, i6400_fpu_apu")
>>
>> -;; min, max
>> +;; min, max, fclass
>>  (define_insn_reservation "i6400_fpu_minmax" 2
>>    (and (eq_attr "cpu" "i6400")
>> -       (eq_attr "type" "fminmax"))
>> +       (eq_attr "type" "fminmax,fclass"))
>>    "i6400_fpu_short+i6400_fpu_logic")
>>
>> -;; fadd, fsub, fcvt
>> +;; fadd, fsub, fcvt, frint
>>  (define_insn_reservation "i6400_fpu_fadd" 4
>>    (and (eq_attr "cpu" "i6400")
>> -       (eq_attr "type" "fadd,fcvt"))
>> +       (eq_attr "type" "fadd,fcvt,frint"))
>>    "i6400_fpu_long, i6400_fpu_apu")
>>
>>  ;; fmul
>> diff --git a/gcc/config/mips/mips.cc b/gcc/config/mips/mips.cc
>> index 6c797b62164..14a1f23eb70 100644
>> --- a/gcc/config/mips/mips.cc
>> +++ b/gcc/config/mips/mips.cc
>> @@ -15775,6 +15775,7 @@ AVAIL_NON_MIPS16 (dspr2_32, !TARGET_64BIT && TARGET_DSPR2)
>>  AVAIL_NON_MIPS16 (loongson, TARGET_LOONGSON_MMI)
>>  AVAIL_MIPS16E2_OR_NON_MIPS16 (cache, TARGET_CACHE_BUILTIN)
>>  AVAIL_NON_MIPS16 (msa, TARGET_MSA)
>> +AVAIL_NON_MIPS16 (r6, mips_isa_rev >= 6)
>>
>>  /* Construct a mips_builtin_description from the given arguments.
>>
>> @@ -15940,6 +15941,14 @@ AVAIL_NON_MIPS16 (msa, TARGET_MSA)
>>      "__builtin_msa_" #INSN,  MIPS_BUILTIN_DIRECT_NO_TARGET,            \
>>      FUNCTION_TYPE, mips_builtin_avail_msa, false }
>>
>> +/* Define a MIPSr6 MIPS_BUILTIN_DIRECT pure function __builtin_mipsr6_<INSN>
>> +   for instruction CODE_FOR_mipsr6_<INSN>.  FUNCTION_TYPE is a builtin_description
>> +   field.  */
>> +#define MIPSR6_BUILTIN_PURE(INSN, FUNCTION_TYPE)                       \
>> +    { CODE_FOR_mipsr6_ ## INSN, MIPS_FP_COND_f,                                \
>> +    "__builtin_mipsr6_" #INSN,  MIPS_BUILTIN_DIRECT,                   \
>> +    FUNCTION_TYPE, mips_builtin_avail_r6, true }
>> +
>>  #define CODE_FOR_mips_sqrt_ps CODE_FOR_sqrtv2sf2
>>  #define CODE_FOR_mips_addq_ph CODE_FOR_addv2hi3
>>  #define CODE_FOR_mips_addu_qb CODE_FOR_addv4qi3
>> @@ -16177,6 +16186,15 @@ AVAIL_NON_MIPS16 (msa, TARGET_MSA)
>>  #define CODE_FOR_msa_ldi_w CODE_FOR_msa_ldiv4si
>>  #define CODE_FOR_msa_ldi_d CODE_FOR_msa_ldiv2di
>>
>> +#define CODE_FOR_mipsr6_min_a_s CODE_FOR_fmin_a_sf
>> +#define CODE_FOR_mipsr6_min_a_d CODE_FOR_fmin_a_df
>> +#define CODE_FOR_mipsr6_max_a_s CODE_FOR_fmax_a_sf
>> +#define CODE_FOR_mipsr6_max_a_d CODE_FOR_fmax_a_df
>> +#define CODE_FOR_mipsr6_rint_s CODE_FOR_frint_sf
>> +#define CODE_FOR_mipsr6_rint_d CODE_FOR_frint_df
>> +#define CODE_FOR_mipsr6_class_s CODE_FOR_fclass_sf
>> +#define CODE_FOR_mipsr6_class_d CODE_FOR_fclass_df
>> +
>>  static const struct mips_builtin_description mips_builtins[] = {
>>  #define MIPS_GET_FCSR 0
>>    DIRECT_BUILTIN (get_fcsr, MIPS_USI_FTYPE_VOID, hard_float),
>> @@ -16998,6 +17016,16 @@ static const struct mips_builtin_description mips_builtins[] = {
>>    MSA_NO_TARGET_BUILTIN (ctcmsa, MIPS_VOID_FTYPE_UQI_SI),
>>    MSA_BUILTIN_PURE (cfcmsa, MIPS_SI_FTYPE_UQI),
>>    MSA_BUILTIN_PURE (move_v, MIPS_V16QI_FTYPE_V16QI),
>> +
>> +  /* Built-in functions for MIPSr6.  */
>> +  MIPSR6_BUILTIN_PURE (min_a_s, MIPS_SF_FTYPE_SF_SF),
>> +  MIPSR6_BUILTIN_PURE (min_a_d, MIPS_DF_FTYPE_DF_DF),
>> +  MIPSR6_BUILTIN_PURE (max_a_s, MIPS_SF_FTYPE_SF_SF),
>> +  MIPSR6_BUILTIN_PURE (max_a_d, MIPS_DF_FTYPE_DF_DF),
>> +  MIPSR6_BUILTIN_PURE (rint_s, MIPS_SF_FTYPE_SF),
>> +  MIPSR6_BUILTIN_PURE (rint_d, MIPS_DF_FTYPE_DF),
>> +  MIPSR6_BUILTIN_PURE (class_s, MIPS_SF_FTYPE_SF),
>> +  MIPSR6_BUILTIN_PURE (class_d, MIPS_DF_FTYPE_DF),
>>  };
>>
>>  /* Index I is the function declaration for mips_builtins[I], or null if the
>> diff --git a/gcc/config/mips/mips.h b/gcc/config/mips/mips.h
>> index 84dd64d98a0..b4bb99e19b1 100644
>> --- a/gcc/config/mips/mips.h
>> +++ b/gcc/config/mips/mips.h
>> @@ -1264,6 +1264,10 @@ struct mips_cpu_info {
>>
>>  #define ISA_HAS_FMIN_FMAX      (mips_isa_rev >= 6)
>>
>> +#define ISA_HAS_FRINT          (mips_isa_rev >= 6)
>> +
>> +#define ISA_HAS_FCLASS         (mips_isa_rev >= 6)
>> +
>>  /* ISA has data indexed prefetch instructions.  This controls use of
>>     'prefx', along with TARGET_HARD_FLOAT and TARGET_DOUBLE_FLOAT.
>>     (prefx is a cop1x instruction, so can only be used if FP is
>> diff --git a/gcc/config/mips/mips.md b/gcc/config/mips/mips.md
>> index 737d2566ec8..297c5141b1f 100644
>> --- a/gcc/config/mips/mips.md
>> +++ b/gcc/config/mips/mips.md
>> @@ -100,6 +100,8 @@
>>    ;; Floating-point unspecs.
>>    UNSPEC_FMIN
>>    UNSPEC_FMAX
>> +  UNSPEC_FRINT
>> +  UNSPEC_FCLASS
>>
>>    ;; HI/LO moves.
>>    UNSPEC_MFHI
>> @@ -375,6 +377,8 @@
>>  ;; frsqrt1      floating point reciprocal square root step1
>>  ;; frsqrt2      floating point reciprocal square root step2
>>  ;; fminmax      floating point min/max
>> +;; frint        floating point round to integral
>> +;; fclass       floating point class mask
>>  ;; dspmac       DSP MAC instructions not saturating the accumulator
>>  ;; dspmacsat    DSP MAC instructions that saturate the accumulator
>>  ;; accext       DSP accumulator extract instructions
>> @@ -392,8 +396,8 @@
>>     prefetch,prefetchx,condmove,mtc,mfc,mthi,mtlo,mfhi,mflo,const,arith,logical,
>>     shift,slt,signext,clz,pop,trap,imul,imul3,imul3nc,imadd,idiv,idiv3,move,
>>     fmove,fadd,fmul,fmadd,fdiv,frdiv,frdiv1,frdiv2,fabs,fneg,fcmp,fcvt,fsqrt,
>> -   frsqrt,frsqrt1,frsqrt2,fminmax,dspmac,dspmacsat,accext,accmod,dspalu,
>> -   dspalusat,multi,atomic,syncloop,nop,ghost,multimem,
>> +   frsqrt,frsqrt1,frsqrt2,fminmax,frint,fclass,dspmac,dspmacsat,accext,
>> +   accmod,dspalu,dspalusat,multi,atomic,syncloop,nop,ghost,multimem,
>>     simd_div,simd_fclass,simd_flog2,simd_fadd,simd_fcvt,simd_fmul,simd_fmadd,
>>     simd_fdiv,simd_bitins,simd_bitmov,simd_insert,simd_sld,simd_mul,simd_fcmp,
>>     simd_fexp2,simd_int_arith,simd_bit,simd_shift,simd_splat,simd_fill,
>> @@ -8007,6 +8011,50 @@
>>    [(set_attr "type" "fminmax")
>>    (set_attr "mode" "<UNITMODE>")])
>>
>> +(define_insn "fmin_a_<mode>"
>> +  [(set (match_operand:SCALARF 0 "register_operand" "=f")
>> +    (if_then_else
>> +       (lt (abs:SCALARF (match_operand:SCALARF 1 "register_operand" "f"))
>> +           (abs:SCALARF (match_operand:SCALARF 2 "register_operand" "f")))
>> +       (match_dup 1)
>> +       (match_dup 2)))]
>> +  "ISA_HAS_FMIN_FMAX"
>> +  "mina.<fmt>\t%0,%1,%2"
>> +  [(set_attr "type" "fminmax")
>> +   (set_attr "mode" "<UNITMODE>")])
>> +
>> +(define_insn "fmax_a_<mode>"
>> +  [(set (match_operand:SCALARF 0 "register_operand" "=f")
>> +    (if_then_else
>> +       (gt (abs:SCALARF (match_operand:SCALARF 1 "register_operand" "f"))
>> +           (abs:SCALARF (match_operand:SCALARF 2 "register_operand" "f")))
>> +       (match_dup 1)
>> +       (match_dup 2)))]
>> +  "ISA_HAS_FMIN_FMAX"
>> +  "maxa.<fmt>\t%0,%1,%2"
>> +  [(set_attr "type" "fminmax")
>> +   (set_attr "mode" "<UNITMODE>")])
>> +
>> +;;Float point round to integral
>> +(define_insn "frint_<mode>"
>> +  [(set (match_operand:SCALARF 0 "register_operand" "=f")
>> +       (unspec:SCALARF [(match_operand:SCALARF 1 "register_operand" "f")]
>> +                       UNSPEC_FRINT))]
>> +  "ISA_HAS_FRINT"
>> +  "rint.<fmt>\t%0,%1"
>> +  [(set_attr "type" "frint")
>> +   (set_attr "mode" "<UNITMODE>")])
>> +
>> +;;Float point class mask
>> +(define_insn "fclass_<mode>"
>> +  [(set (match_operand:SCALARF 0 "register_operand" "=f")
>> +       (unspec:SCALARF [(match_operand:SCALARF 1 "register_operand" "f")]
>> +                       UNSPEC_FCLASS))]
>> +  "ISA_HAS_FCLASS"
>> +  "class.<fmt>\t%0,%1"
>> +  [(set_attr "type" "fclass")
>> +   (set_attr "mode" "<UNITMODE>")])
>> +
>>  ;; 2 HI loads are joined.
>>  (define_peephole2
>>    [(set (match_operand:SI 0 "register_operand")
>> diff --git a/gcc/config/mips/p6600.md b/gcc/config/mips/p6600.md
>> index b6cb554939a..d541e98fdec 100644
>> --- a/gcc/config/mips/p6600.md
>> +++ b/gcc/config/mips/p6600.md
>> @@ -161,16 +161,16 @@
>>  ;; FPU pipe
>>  ;;
>>
>> -;; fadd, fsub
>> +;; fadd, fsub, frint
>>  (define_insn_reservation "p6600_fpu_fadd" 4
>>    (and (eq_attr "cpu" "p6600")
>> -       (eq_attr "type" "fadd"))
>> +       (eq_attr "type" "fadd,frint"))
>>    "p6600_fpu_long, p6600_fpu_apu")
>>
>> -;; fabs, fneg, fcmp, fminmax
>> +;; fabs, fneg, fcmp, fminmax, fclass
>>  (define_insn_reservation "p6600_fpu_fabs" 2
>>    (and (eq_attr "cpu" "p6600")
>> -       (ior (eq_attr "type" "fabs,fneg,fcmp,fmove,fminmax")
>> +       (ior (eq_attr "type" "fabs,fneg,fcmp,fmove,fminmax,fclass")
>>            (and (eq_attr "type" "condmove")
>>                 (eq_attr "mode" "SF,DF"))))
>>    "p6600_fpu_short, p6600_fpu_apu")
>> diff --git a/gcc/testsuite/gcc.target/mips/mips-class.c b/gcc/testsuite/gcc.target/mips/mips-class.c
>> new file mode 100644
>> index 00000000000..e71a853fb8c
>> --- /dev/null
>> +++ b/gcc/testsuite/gcc.target/mips/mips-class.c
>> @@ -0,0 +1,17 @@
>> +/* { dg-do compile } */
>> +/* { dg-options "-mhard-float -march=mips32r6" } */
>> +
>> +NOMIPS16 float
>> +test01 (float a)
>> +{
>> +  return __builtin_mipsr6_class_s (a);
>> +}
>> +
>> +NOMIPS16 double
>> +test02 (double a)
>> +{
>> +  return __builtin_mipsr6_class_d (a);
>> +}
>> +
>> +/* { dg-final { scan-assembler "class\\.s" } } */
>> +/* { dg-final { scan-assembler "class\\.d" } } */
>> diff --git a/gcc/testsuite/gcc.target/mips/mips-minamaxa.c b/gcc/testsuite/gcc.target/mips/mips-minamaxa.c
>> new file mode 100644
>> index 00000000000..d41d6078779
>> --- /dev/null
>> +++ b/gcc/testsuite/gcc.target/mips/mips-minamaxa.c
>> @@ -0,0 +1,31 @@
>> +/* { dg-do compile } */
>> +/* { dg-options "-mhard-float -march=mips32r6" } */
>> +
>> +NOMIPS16 float
>> +test01 (float a, float b)
>> +{
>> +  return __builtin_mipsr6_min_a_s (a, b);
>> +}
>> +
>> +NOMIPS16 double
>> +test02 (double a, double b)
>> +{
>> +  return __builtin_mipsr6_min_a_d (a, b);
>> +}
>> +
>> +NOMIPS16 float
>> +test03 (float a, float b)
>> +{
>> +  return __builtin_mipsr6_max_a_s (a, b);
>> +}
>> +
>> +NOMIPS16 double
>> +test04 (double a, double b)
>> +{
>> +  return __builtin_mipsr6_max_a_d (a, b);
>> +}
>> +
>> +/* { dg-final { scan-assembler "mina\\.s" } } */
>> +/* { dg-final { scan-assembler "mina\\.d" } } */
>> +/* { dg-final { scan-assembler "maxa\\.s" } } */
>> +/* { dg-final { scan-assembler "maxa\\.d" } } */
>> diff --git a/gcc/testsuite/gcc.target/mips/mips-rint.c b/gcc/testsuite/gcc.target/mips/mips-rint.c
>> new file mode 100644
>> index 00000000000..a964b8c4267
>> --- /dev/null
>> +++ b/gcc/testsuite/gcc.target/mips/mips-rint.c
>> @@ -0,0 +1,17 @@
>> +/* { dg-do compile } */
>> +/* { dg-options "-mhard-float -march=mips32r6" } */
>> +
>> +NOMIPS16 float
>> +test01 (float a)
>> +{
>> +  return __builtin_mipsr6_rint_s (a);
>> +}
>> +
>> +NOMIPS16 double
>> +test02 (double a)
>> +{
>> +  return __builtin_mipsr6_rint_d (a);
>> +}
>> +
>> +/* { dg-final { scan-assembler "rint\\.s" } } */
>> +/* { dg-final { scan-assembler "rint\\.d" } } */
>> --
>> 2.41.0
Xi Ruoyao Sept. 10, 2024, 9:30 a.m. UTC | #3
On Tue, 2024-09-10 at 16:50 +0800, 梅杰 wrote:
> As for the function `__builtin_rint`, although it exists, however, after 
> defining the instruction in `mips.md`, GCC still won't generate `RINT.fmt` 
> instruction for MIPS, it generates following code instead:
> 
> > 	lui     $28,%hi(__gnu_local_gp)
> > 	addiu   $28,$28,%lo(__gnu_local_gp)
> > 	lw      $25,%call16(rint)($28)
> > 	.reloc  1f,R_MIPS_JALR,rint

Why?

Whis this:

diff --git a/gcc/config/mips/mips.md b/gcc/config/mips/mips.md
index f147667d63a..0c1ef77a816 100644
--- a/gcc/config/mips/mips.md
+++ b/gcc/config/mips/mips.md
@@ -100,6 +100,7 @@ (define_c_enum "unspec" [
   ;; Floating-point unspecs.
   UNSPEC_FMIN
   UNSPEC_FMAX
+  UNSPEC_RINT
 
   ;; HI/LO moves.
   UNSPEC_MFHI
@@ -8025,6 +8026,14 @@ (define_peephole2
 		   (any_extend:SI (match_dup 3)))])]
   "")
 
+(define_insn "rint<mode>2"
+  [(set (match_operand:SCALARF 0 "register_operand" "=f")
+	(unspec:SCALARF [(match_operand:SCALARF 1 "register_operand" " f")]
+			UNSPEC_RINT))]
+  "mips_isa_rev >= 6"
+  "rint.<fmt>\t%0,%1")
+
+
 

 ;; Synchronization instructions.

it works for me:

$ cat t.c
double test(double x)
{
	return __builtin_rint(x);
}
$ ./gcc/cc1 t.c -nostdinc -O2 -mips64r6 -mexplicit-relocs -mabi=64
$ grep rint t.s
	rint.d	$f0,$f12
Jie Mei Sept. 11, 2024, 8:17 a.m. UTC | #4
在 2024/9/10 17:30, Xi Ruoyao 写道:
> On Tue, 2024-09-10 at 16:50 +0800, 梅杰 wrote:
>> As for the function `__builtin_rint`, although it exists, however, after 
>> defining the instruction in `mips.md`, GCC still won't generate `RINT.fmt` 
>> instruction for MIPS, it generates following code instead:
>>
>>> 	lui     $28,%hi(__gnu_local_gp)
>>> 	addiu   $28,$28,%lo(__gnu_local_gp)
>>> 	lw      $25,%call16(rint)($28)
>>> 	.reloc  1f,R_MIPS_JALR,rint
> 
> Why?
> 
> Whis this:
> 
> diff --git a/gcc/config/mips/mips.md b/gcc/config/mips/mips.md
> index f147667d63a..0c1ef77a816 100644
> --- a/gcc/config/mips/mips.md
> +++ b/gcc/config/mips/mips.md
> @@ -100,6 +100,7 @@ (define_c_enum "unspec" [
>    ;; Floating-point unspecs.
>    UNSPEC_FMIN
>    UNSPEC_FMAX
> +  UNSPEC_RINT
>  
>    ;; HI/LO moves.
>    UNSPEC_MFHI
> @@ -8025,6 +8026,14 @@ (define_peephole2
>  		   (any_extend:SI (match_dup 3)))])]
>    "")
>  
> +(define_insn "rint<mode>2"
> +  [(set (match_operand:SCALARF 0 "register_operand" "=f")
> +	(unspec:SCALARF [(match_operand:SCALARF 1 "register_operand" " f")]
> +			UNSPEC_RINT))]
> +  "mips_isa_rev >= 6"
> +  "rint.<fmt>\t%0,%1")
> +
> +
>  
> 
>  ;; Synchronization instructions.
> 
> it works for me:

Yes, you are right!

I have applied this patch into my current code and I can confirm that
by changing `frint_<mode>` to `rint<mode>2` works. GCC will generate 
`RINT.fmt` instruction correctly with built-in funtion `__builtin_rint`
after applying the patch.

Maybe you can write a patch for `RINT.fmt`? I will update this patch and 
remove code related to `RINT.fmt`, if you could do that. At the same time, 
could anyone review the rest of this patch? Thanks!
Xi Ruoyao Sept. 11, 2024, 11:06 a.m. UTC | #5
On Wed, 2024-09-11 at 16:17 +0800, 梅杰 wrote:
> 在 2024/9/10 17:30, Xi Ruoyao 写道:
> > On Tue, 2024-09-10 at 16:50 +0800, 梅杰 wrote:
> > > As for the function `__builtin_rint`, although it exists, however, after 
> > > defining the instruction in `mips.md`, GCC still won't generate `RINT.fmt` 
> > > instruction for MIPS, it generates following code instead:
> > > 
> > > > 	lui     $28,%hi(__gnu_local_gp)
> > > > 	addiu   $28,$28,%lo(__gnu_local_gp)
> > > > 	lw      $25,%call16(rint)($28)
> > > > 	.reloc  1f,R_MIPS_JALR,rint
> > 
> > Why?
> > 
> > Whis this:
> > 
> > diff --git a/gcc/config/mips/mips.md b/gcc/config/mips/mips.md
> > index f147667d63a..0c1ef77a816 100644
> > --- a/gcc/config/mips/mips.md
> > +++ b/gcc/config/mips/mips.md
> > @@ -100,6 +100,7 @@ (define_c_enum "unspec" [
> >    ;; Floating-point unspecs.
> >    UNSPEC_FMIN
> >    UNSPEC_FMAX
> > +  UNSPEC_RINT
> >  
> >    ;; HI/LO moves.
> >    UNSPEC_MFHI
> > @@ -8025,6 +8026,14 @@ (define_peephole2
> >  		   (any_extend:SI (match_dup 3)))])]
> >    "")
> >  
> > +(define_insn "rint<mode>2"
> > +  [(set (match_operand:SCALARF 0 "register_operand" "=f")
> > +	(unspec:SCALARF [(match_operand:SCALARF 1 "register_operand" " f")]
> > +			UNSPEC_RINT))]
> > +  "mips_isa_rev >= 6"
> > +  "rint.<fmt>\t%0,%1")
> > +
> > +
> >  
> > 
> >  ;; Synchronization instructions.
> > 
> > it works for me:
> 
> Yes, you are right!
> 
> I have applied this patch into my current code and I can confirm that
> by changing `frint_<mode>` to `rint<mode>2` works. GCC will generate 
> `RINT.fmt` instruction correctly with built-in funtion `__builtin_rint`
> after applying the patch.
> 
> Maybe you can write a patch for `RINT.fmt`? I will update this patch and 
> remove code related to `RINT.fmt`, if you could do that. At the same time, 
> could anyone review the rest of this patch? Thanks!

You can use my code in your v2 patch w/o attribution (or with a Co-
authored-by if you'd like to attribute anyway).  I don't have an r6
hardware and I don't like testing my change solely based on an emulator,
so I'd not send a patch myself.
diff mbox series

Patch

diff --git a/gcc/config/mips/i6400.md b/gcc/config/mips/i6400.md
index d6f691ee217..48ce980e1c2 100644
--- a/gcc/config/mips/i6400.md
+++ b/gcc/config/mips/i6400.md
@@ -219,16 +219,16 @@ 
        (eq_attr "type" "fabs,fneg,fmove"))
   "i6400_fpu_short, i6400_fpu_apu")
 
-;; min, max
+;; min, max, fclass
 (define_insn_reservation "i6400_fpu_minmax" 2
   (and (eq_attr "cpu" "i6400")
-       (eq_attr "type" "fminmax"))
+       (eq_attr "type" "fminmax,fclass"))
   "i6400_fpu_short+i6400_fpu_logic")
 
-;; fadd, fsub, fcvt
+;; fadd, fsub, fcvt, frint
 (define_insn_reservation "i6400_fpu_fadd" 4
   (and (eq_attr "cpu" "i6400")
-       (eq_attr "type" "fadd,fcvt"))
+       (eq_attr "type" "fadd,fcvt,frint"))
   "i6400_fpu_long, i6400_fpu_apu")
 
 ;; fmul
diff --git a/gcc/config/mips/mips.cc b/gcc/config/mips/mips.cc
index 6c797b62164..14a1f23eb70 100644
--- a/gcc/config/mips/mips.cc
+++ b/gcc/config/mips/mips.cc
@@ -15775,6 +15775,7 @@  AVAIL_NON_MIPS16 (dspr2_32, !TARGET_64BIT && TARGET_DSPR2)
 AVAIL_NON_MIPS16 (loongson, TARGET_LOONGSON_MMI)
 AVAIL_MIPS16E2_OR_NON_MIPS16 (cache, TARGET_CACHE_BUILTIN)
 AVAIL_NON_MIPS16 (msa, TARGET_MSA)
+AVAIL_NON_MIPS16 (r6, mips_isa_rev >= 6)
 
 /* Construct a mips_builtin_description from the given arguments.
 
@@ -15940,6 +15941,14 @@  AVAIL_NON_MIPS16 (msa, TARGET_MSA)
     "__builtin_msa_" #INSN,  MIPS_BUILTIN_DIRECT_NO_TARGET,		\
     FUNCTION_TYPE, mips_builtin_avail_msa, false }
 
+/* Define a MIPSr6 MIPS_BUILTIN_DIRECT pure function __builtin_mipsr6_<INSN>
+   for instruction CODE_FOR_mipsr6_<INSN>.  FUNCTION_TYPE is a builtin_description
+   field.  */
+#define MIPSR6_BUILTIN_PURE(INSN, FUNCTION_TYPE)			\
+    { CODE_FOR_mipsr6_ ## INSN, MIPS_FP_COND_f,				\
+    "__builtin_mipsr6_" #INSN,  MIPS_BUILTIN_DIRECT,			\
+    FUNCTION_TYPE, mips_builtin_avail_r6, true }
+
 #define CODE_FOR_mips_sqrt_ps CODE_FOR_sqrtv2sf2
 #define CODE_FOR_mips_addq_ph CODE_FOR_addv2hi3
 #define CODE_FOR_mips_addu_qb CODE_FOR_addv4qi3
@@ -16177,6 +16186,15 @@  AVAIL_NON_MIPS16 (msa, TARGET_MSA)
 #define CODE_FOR_msa_ldi_w CODE_FOR_msa_ldiv4si
 #define CODE_FOR_msa_ldi_d CODE_FOR_msa_ldiv2di
 
+#define CODE_FOR_mipsr6_min_a_s CODE_FOR_fmin_a_sf
+#define CODE_FOR_mipsr6_min_a_d CODE_FOR_fmin_a_df
+#define CODE_FOR_mipsr6_max_a_s CODE_FOR_fmax_a_sf
+#define CODE_FOR_mipsr6_max_a_d CODE_FOR_fmax_a_df
+#define CODE_FOR_mipsr6_rint_s CODE_FOR_frint_sf
+#define CODE_FOR_mipsr6_rint_d CODE_FOR_frint_df
+#define CODE_FOR_mipsr6_class_s CODE_FOR_fclass_sf
+#define CODE_FOR_mipsr6_class_d CODE_FOR_fclass_df
+
 static const struct mips_builtin_description mips_builtins[] = {
 #define MIPS_GET_FCSR 0
   DIRECT_BUILTIN (get_fcsr, MIPS_USI_FTYPE_VOID, hard_float),
@@ -16998,6 +17016,16 @@  static const struct mips_builtin_description mips_builtins[] = {
   MSA_NO_TARGET_BUILTIN (ctcmsa, MIPS_VOID_FTYPE_UQI_SI),
   MSA_BUILTIN_PURE (cfcmsa, MIPS_SI_FTYPE_UQI),
   MSA_BUILTIN_PURE (move_v, MIPS_V16QI_FTYPE_V16QI),
+
+  /* Built-in functions for MIPSr6.  */
+  MIPSR6_BUILTIN_PURE (min_a_s, MIPS_SF_FTYPE_SF_SF),
+  MIPSR6_BUILTIN_PURE (min_a_d, MIPS_DF_FTYPE_DF_DF),
+  MIPSR6_BUILTIN_PURE (max_a_s, MIPS_SF_FTYPE_SF_SF),
+  MIPSR6_BUILTIN_PURE (max_a_d, MIPS_DF_FTYPE_DF_DF),
+  MIPSR6_BUILTIN_PURE (rint_s, MIPS_SF_FTYPE_SF),
+  MIPSR6_BUILTIN_PURE (rint_d, MIPS_DF_FTYPE_DF),
+  MIPSR6_BUILTIN_PURE (class_s, MIPS_SF_FTYPE_SF),
+  MIPSR6_BUILTIN_PURE (class_d, MIPS_DF_FTYPE_DF),
 };
 
 /* Index I is the function declaration for mips_builtins[I], or null if the
diff --git a/gcc/config/mips/mips.h b/gcc/config/mips/mips.h
index 84dd64d98a0..b4bb99e19b1 100644
--- a/gcc/config/mips/mips.h
+++ b/gcc/config/mips/mips.h
@@ -1264,6 +1264,10 @@  struct mips_cpu_info {
 
 #define ISA_HAS_FMIN_FMAX	(mips_isa_rev >= 6)
 
+#define ISA_HAS_FRINT		(mips_isa_rev >= 6) 
+
+#define ISA_HAS_FCLASS		(mips_isa_rev >= 6) 
+
 /* ISA has data indexed prefetch instructions.  This controls use of
    'prefx', along with TARGET_HARD_FLOAT and TARGET_DOUBLE_FLOAT.
    (prefx is a cop1x instruction, so can only be used if FP is
diff --git a/gcc/config/mips/mips.md b/gcc/config/mips/mips.md
index 737d2566ec8..297c5141b1f 100644
--- a/gcc/config/mips/mips.md
+++ b/gcc/config/mips/mips.md
@@ -100,6 +100,8 @@ 
   ;; Floating-point unspecs.
   UNSPEC_FMIN
   UNSPEC_FMAX
+  UNSPEC_FRINT
+  UNSPEC_FCLASS
 
   ;; HI/LO moves.
   UNSPEC_MFHI
@@ -375,6 +377,8 @@ 
 ;; frsqrt1      floating point reciprocal square root step1
 ;; frsqrt2      floating point reciprocal square root step2
 ;; fminmax      floating point min/max
+;; frint        floating point round to integral
+;; fclass       floating point class mask
 ;; dspmac       DSP MAC instructions not saturating the accumulator
 ;; dspmacsat    DSP MAC instructions that saturate the accumulator
 ;; accext       DSP accumulator extract instructions
@@ -392,8 +396,8 @@ 
    prefetch,prefetchx,condmove,mtc,mfc,mthi,mtlo,mfhi,mflo,const,arith,logical,
    shift,slt,signext,clz,pop,trap,imul,imul3,imul3nc,imadd,idiv,idiv3,move,
    fmove,fadd,fmul,fmadd,fdiv,frdiv,frdiv1,frdiv2,fabs,fneg,fcmp,fcvt,fsqrt,
-   frsqrt,frsqrt1,frsqrt2,fminmax,dspmac,dspmacsat,accext,accmod,dspalu,
-   dspalusat,multi,atomic,syncloop,nop,ghost,multimem,
+   frsqrt,frsqrt1,frsqrt2,fminmax,frint,fclass,dspmac,dspmacsat,accext,
+   accmod,dspalu,dspalusat,multi,atomic,syncloop,nop,ghost,multimem,
    simd_div,simd_fclass,simd_flog2,simd_fadd,simd_fcvt,simd_fmul,simd_fmadd,
    simd_fdiv,simd_bitins,simd_bitmov,simd_insert,simd_sld,simd_mul,simd_fcmp,
    simd_fexp2,simd_int_arith,simd_bit,simd_shift,simd_splat,simd_fill,
@@ -8007,6 +8011,50 @@ 
   [(set_attr "type" "fminmax")
   (set_attr "mode" "<UNITMODE>")])
 
+(define_insn "fmin_a_<mode>"
+  [(set (match_operand:SCALARF 0 "register_operand" "=f")
+    (if_then_else
+       (lt (abs:SCALARF (match_operand:SCALARF 1 "register_operand" "f"))
+           (abs:SCALARF (match_operand:SCALARF 2 "register_operand" "f")))
+       (match_dup 1)
+       (match_dup 2)))]
+  "ISA_HAS_FMIN_FMAX"
+  "mina.<fmt>\t%0,%1,%2"
+  [(set_attr "type" "fminmax")
+   (set_attr "mode" "<UNITMODE>")])
+
+(define_insn "fmax_a_<mode>"
+  [(set (match_operand:SCALARF 0 "register_operand" "=f")
+    (if_then_else
+       (gt (abs:SCALARF (match_operand:SCALARF 1 "register_operand" "f"))
+           (abs:SCALARF (match_operand:SCALARF 2 "register_operand" "f")))
+       (match_dup 1)
+       (match_dup 2)))]
+  "ISA_HAS_FMIN_FMAX"
+  "maxa.<fmt>\t%0,%1,%2"
+  [(set_attr "type" "fminmax")
+   (set_attr "mode" "<UNITMODE>")])
+
+;;Float point round to integral
+(define_insn "frint_<mode>"
+  [(set (match_operand:SCALARF 0 "register_operand" "=f")
+	(unspec:SCALARF [(match_operand:SCALARF 1 "register_operand" "f")]
+			UNSPEC_FRINT))]
+  "ISA_HAS_FRINT"
+  "rint.<fmt>\t%0,%1"
+  [(set_attr "type" "frint")
+   (set_attr "mode" "<UNITMODE>")])
+
+;;Float point class mask
+(define_insn "fclass_<mode>"
+  [(set (match_operand:SCALARF 0 "register_operand" "=f")
+	(unspec:SCALARF [(match_operand:SCALARF 1 "register_operand" "f")]
+			UNSPEC_FCLASS))]
+  "ISA_HAS_FCLASS"
+  "class.<fmt>\t%0,%1"
+  [(set_attr "type" "fclass")
+   (set_attr "mode" "<UNITMODE>")])
+
 ;; 2 HI loads are joined.
 (define_peephole2
   [(set (match_operand:SI 0 "register_operand")
diff --git a/gcc/config/mips/p6600.md b/gcc/config/mips/p6600.md
index b6cb554939a..d541e98fdec 100644
--- a/gcc/config/mips/p6600.md
+++ b/gcc/config/mips/p6600.md
@@ -161,16 +161,16 @@ 
 ;; FPU pipe
 ;;
 
-;; fadd, fsub
+;; fadd, fsub, frint
 (define_insn_reservation "p6600_fpu_fadd" 4
   (and (eq_attr "cpu" "p6600")
-       (eq_attr "type" "fadd"))
+       (eq_attr "type" "fadd,frint"))
   "p6600_fpu_long, p6600_fpu_apu")
 
-;; fabs, fneg, fcmp, fminmax
+;; fabs, fneg, fcmp, fminmax, fclass
 (define_insn_reservation "p6600_fpu_fabs" 2
   (and (eq_attr "cpu" "p6600")
-       (ior (eq_attr "type" "fabs,fneg,fcmp,fmove,fminmax")
+       (ior (eq_attr "type" "fabs,fneg,fcmp,fmove,fminmax,fclass")
 	   (and (eq_attr "type" "condmove")
 		(eq_attr "mode" "SF,DF"))))
   "p6600_fpu_short, p6600_fpu_apu")
diff --git a/gcc/testsuite/gcc.target/mips/mips-class.c b/gcc/testsuite/gcc.target/mips/mips-class.c
new file mode 100644
index 00000000000..e71a853fb8c
--- /dev/null
+++ b/gcc/testsuite/gcc.target/mips/mips-class.c
@@ -0,0 +1,17 @@ 
+/* { dg-do compile } */
+/* { dg-options "-mhard-float -march=mips32r6" } */
+
+NOMIPS16 float
+test01 (float a)
+{
+  return __builtin_mipsr6_class_s (a);
+}
+
+NOMIPS16 double
+test02 (double a)
+{
+  return __builtin_mipsr6_class_d (a);
+}
+
+/* { dg-final { scan-assembler "class\\.s" } } */
+/* { dg-final { scan-assembler "class\\.d" } } */
diff --git a/gcc/testsuite/gcc.target/mips/mips-minamaxa.c b/gcc/testsuite/gcc.target/mips/mips-minamaxa.c
new file mode 100644
index 00000000000..d41d6078779
--- /dev/null
+++ b/gcc/testsuite/gcc.target/mips/mips-minamaxa.c
@@ -0,0 +1,31 @@ 
+/* { dg-do compile } */
+/* { dg-options "-mhard-float -march=mips32r6" } */
+
+NOMIPS16 float
+test01 (float a, float b)
+{
+  return __builtin_mipsr6_min_a_s (a, b);
+}
+
+NOMIPS16 double
+test02 (double a, double b)
+{
+  return __builtin_mipsr6_min_a_d (a, b);
+}
+
+NOMIPS16 float
+test03 (float a, float b)
+{
+  return __builtin_mipsr6_max_a_s (a, b);
+}
+
+NOMIPS16 double
+test04 (double a, double b)
+{
+  return __builtin_mipsr6_max_a_d (a, b);
+}
+
+/* { dg-final { scan-assembler "mina\\.s" } } */
+/* { dg-final { scan-assembler "mina\\.d" } } */
+/* { dg-final { scan-assembler "maxa\\.s" } } */
+/* { dg-final { scan-assembler "maxa\\.d" } } */
diff --git a/gcc/testsuite/gcc.target/mips/mips-rint.c b/gcc/testsuite/gcc.target/mips/mips-rint.c
new file mode 100644
index 00000000000..a964b8c4267
--- /dev/null
+++ b/gcc/testsuite/gcc.target/mips/mips-rint.c
@@ -0,0 +1,17 @@ 
+/* { dg-do compile } */
+/* { dg-options "-mhard-float -march=mips32r6" } */
+
+NOMIPS16 float 
+test01 (float a)
+{
+  return __builtin_mipsr6_rint_s (a);
+}
+
+NOMIPS16 double 
+test02 (double a)
+{
+  return __builtin_mipsr6_rint_d (a);
+}
+
+/* { dg-final { scan-assembler "rint\\.s" } } */
+/* { dg-final { scan-assembler "rint\\.d" } } */