[v2] MIPS: Add MIN/MAX.fmt instructions support for MIPS R6
Checks
Context |
Check |
Description |
linaro-tcwg-bot/tcwg_gcc_build--master-aarch64 |
success
|
Testing passed
|
linaro-tcwg-bot/tcwg_gcc_check--master-aarch64 |
success
|
Testing passed
|
linaro-tcwg-bot/tcwg_gcc_build--master-arm |
success
|
Testing passed
|
linaro-tcwg-bot/tcwg_gcc_check--master-arm |
success
|
Testing passed
|
Commit Message
This patch adds the smin/smax RTL mode for the
min/max.fmt instructions.
Also, since the min/max.fmt instrucions applies to the
IEEE 754-2008 "minNum" and "maxNum" operations, this
patch also provides the new "fmin<mode>3" and
"fmax<mode>3" modes.
gcc/ChangeLog:
* config/mips/i6400.md (i6400_fpu_minmax): New
define_insn_reservation.
* config/mips/mips.h (ISA_HAS_FMIN_FMAX): Define new macro.
* config/mips/mips.md (UNSPEC_FMIN): New unspec.
(UNSPEC_FMAX): Same as above.
(type): Add fminmax.
(smin<mode>3): Generates MIN.fmt instructions.
(smax<mode>3): Generates MAX.fmt instructions.
(fmin<mode>3): Generates MIN.fmt instructions.
(fmax<mode>3): Generates MAX.fmt instructions.
* config/mips/p6600.md (p6600_fpu_fabs): Include fminmax
type.
gcc/testsuite/ChangeLog:
* gcc.target/mips/mips-minmax.c: New test for MIPS R6.
---
gcc/config/mips/i6400.md | 6 +++
gcc/config/mips/mips.h | 2 +
gcc/config/mips/mips.md | 50 ++++++++++++++++++++-
gcc/config/mips/p6600.md | 2 +-
gcc/testsuite/gcc.target/mips/mips-minmax.c | 40 +++++++++++++++++
5 files changed, 97 insertions(+), 3 deletions(-)
create mode 100644 gcc/testsuite/gcc.target/mips/mips-minmax.c
Comments
Jie Mei <jie.mei@oss.cipunited.com> 于2024年3月25日周一 17:46写道:
>
> This patch adds the smin/smax RTL mode for the
> min/max.fmt instructions.
>
> Also, since the min/max.fmt instrucions applies to the
> IEEE 754-2008 "minNum" and "maxNum" operations, this
> patch also provides the new "fmin<mode>3" and
> "fmax<mode>3" modes.
>
> gcc/ChangeLog:
>
> * config/mips/i6400.md (i6400_fpu_minmax): New
> define_insn_reservation.
> * config/mips/mips.h (ISA_HAS_FMIN_FMAX): Define new macro.
> * config/mips/mips.md (UNSPEC_FMIN): New unspec.
> (UNSPEC_FMAX): Same as above.
> (type): Add fminmax.
> (smin<mode>3): Generates MIN.fmt instructions.
> (smax<mode>3): Generates MAX.fmt instructions.
> (fmin<mode>3): Generates MIN.fmt instructions.
> (fmax<mode>3): Generates MAX.fmt instructions.
> * config/mips/p6600.md (p6600_fpu_fabs): Include fminmax
> type.
>
> gcc/testsuite/ChangeLog:
>
> * gcc.target/mips/mips-minmax.c: New test for MIPS R6.
> ---
> gcc/config/mips/i6400.md | 6 +++
> gcc/config/mips/mips.h | 2 +
> gcc/config/mips/mips.md | 50 ++++++++++++++++++++-
> gcc/config/mips/p6600.md | 2 +-
> gcc/testsuite/gcc.target/mips/mips-minmax.c | 40 +++++++++++++++++
> 5 files changed, 97 insertions(+), 3 deletions(-)
> create mode 100644 gcc/testsuite/gcc.target/mips/mips-minmax.c
>
> diff --git a/gcc/config/mips/i6400.md b/gcc/config/mips/i6400.md
> index 9f216fe0210..d6f691ee217 100644
> --- a/gcc/config/mips/i6400.md
> +++ b/gcc/config/mips/i6400.md
> @@ -219,6 +219,12 @@
> (eq_attr "type" "fabs,fneg,fmove"))
> "i6400_fpu_short, i6400_fpu_apu")
>
> +;; min, max
> +(define_insn_reservation "i6400_fpu_minmax" 2
> + (and (eq_attr "cpu" "i6400")
> + (eq_attr "type" "fminmax"))
> + "i6400_fpu_short+i6400_fpu_logic")
> +
> ;; fadd, fsub, fcvt
> (define_insn_reservation "i6400_fpu_fadd" 4
> (and (eq_attr "cpu" "i6400")
> diff --git a/gcc/config/mips/mips.h b/gcc/config/mips/mips.h
> index 7145d23c650..5ce984ac99b 100644
> --- a/gcc/config/mips/mips.h
> +++ b/gcc/config/mips/mips.h
> @@ -1259,6 +1259,8 @@ struct mips_cpu_info {
> #define ISA_HAS_9BIT_DISPLACEMENT (mips_isa_rev >= 6 \
> || ISA_HAS_MIPS16E2)
>
> +#define ISA_HAS_FMIN_FMAX (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 b0fb5850a9e..26f758c90dd 100644
> --- a/gcc/config/mips/mips.md
> +++ b/gcc/config/mips/mips.md
> @@ -97,6 +97,10 @@
> UNSPEC_GET_FCSR
> UNSPEC_SET_FCSR
>
> + ;; Floating-point unspecs.
> + UNSPEC_FMIN
> + UNSPEC_FMAX
> +
> ;; HI/LO moves.
> UNSPEC_MFHI
> UNSPEC_MTHI
> @@ -370,6 +374,7 @@
> ;; frsqrt floating point reciprocal square root
> ;; frsqrt1 floating point reciprocal square root step1
> ;; frsqrt2 floating point reciprocal square root step2
> +;; fminmax floating point min/max
> ;; dspmac DSP MAC instructions not saturating the accumulator
> ;; dspmacsat DSP MAC instructions that saturate the accumulator
> ;; accext DSP accumulator extract instructions
> @@ -387,8 +392,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,dspmac,dspmacsat,accext,accmod,dspalu,dspalusat,
> - multi,atomic,syncloop,nop,ghost,multimem,
> + frsqrt,frsqrt1,frsqrt2,fminmax,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,
> @@ -7971,6 +7976,47 @@
> [(set_attr "move_type" "load")
> (set_attr "insn_count" "2")])
>
> +;;
> +;; Float point MIN/MAX
> +;;
> +
> +(define_insn "smin<mode>3"
> + [(set (match_operand:SCALARF 0 "register_operand" "=f")
> + (smin:SCALARF (match_operand:SCALARF 1 "register_operand" "f")
> + (match_operand:SCALARF 2 "register_operand" "f")))]
> + "ISA_HAS_FMIN_FMAX"
> + "min.<fmt>\t%0,%1,%2"
> + [(set_attr "type" "fminmax")
> + (set_attr "mode" "<UNITMODE>")])
> +
> +(define_insn "smax<mode>3"
> + [(set (match_operand:SCALARF 0 "register_operand" "=f")
> + (smax:SCALARF (match_operand:SCALARF 1 "register_operand" "f")
> + (match_operand:SCALARF 2 "register_operand" "f")))]
> + "ISA_HAS_FMIN_FMAX"
> + "max.<fmt>\t%0,%1,%2"
> + [(set_attr "type" "fminmax")
> + (set_attr "mode" "<UNITMODE>")])
> +
> +(define_insn "fmin<mode>3"
> + [(set (match_operand:SCALARF 0 "register_operand" "=f")
> + (unspec:SCALARF [(use (match_operand:SCALARF 1 "register_operand" "f"))
> + (use (match_operand:SCALARF 2 "register_operand" "f"))]
> + UNSPEC_FMIN))]
> + "ISA_HAS_FMIN_FMAX"
> + "min.<fmt>\t%0,%1,%2"
> + [(set_attr "type" "fminmax")
> + (set_attr "mode" "<UNITMODE>")])
> +
> +(define_insn "fmax<mode>3"
> + [(set (match_operand:SCALARF 0 "register_operand" "=f")
> + (unspec:SCALARF [(use (match_operand:SCALARF 1 "register_operand" "f"))
> + (use (match_operand:SCALARF 2 "register_operand" "f"))]
> + UNSPEC_FMAX))]
> + "ISA_HAS_FMIN_FMAX"
> + "max.<fmt>\t%0,%1,%2"
> + [(set_attr "type" "fminmax")
> + (set_attr "mode" "<UNITMODE>")])
>
> ;; 2 HI loads are joined.
> (define_peephole2
> diff --git a/gcc/config/mips/p6600.md b/gcc/config/mips/p6600.md
> index a9e3262cc18..c502f0eb5c6 100644
> --- a/gcc/config/mips/p6600.md
> +++ b/gcc/config/mips/p6600.md
> @@ -170,7 +170,7 @@
> ;; fabs, fneg, fcmp
add `fminmax` here?
> (define_insn_reservation "p6600_fpu_fabs" 2
> (and (eq_attr "cpu" "p6600")
> - (ior (eq_attr "type" "fabs,fneg,fcmp,fmove")
> + (ior (eq_attr "type" "fabs,fneg,fcmp,fmove,fminmax")
> (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-minmax.c b/gcc/testsuite/gcc.target/mips/mips-minmax.c
> new file mode 100644
> index 00000000000..087ed299d8f
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/mips/mips-minmax.c
> @@ -0,0 +1,40 @@
> +/* { dg-do compile } */
> +/* { dg-options "-mhard-float -fno-finite-math-only -march=mips32r6" } */
> +/* { dg-skip-if "code quality test" { *-*-* } { "-O0" } { "" } } */
> +
> +/* Test MIN.D. */
> +
> +/* { dg-final { scan-assembler "\tmin\\.d\t" } } */
> +double
> +test01 (double x, double y)
> +{
> + return __builtin_fmin (x, y);
> +}
> +
> +/* Test MIN.S. */
> +
> +/* { dg-final { scan-assembler "\tmin\\.s\t" } } */
> +float
> +test02 (float x, float y)
> +{
> + return __builtin_fminf (x, y);
> +}
> +
> +/* Test MAX.D. */
> +
> +/* { dg-final { scan-assembler "\tmax\\.d\t" } } */
> +double
> +test03 (double x, double y)
> +{
> + return __builtin_fmax (x, y);
> +}
> +
> +/* Test MAX.S. */
> +
> +/* { dg-final { scan-assembler "\tmax\\.s\t" } } */
> +float
> +test04 (float x, float y)
> +{
> + return __builtin_fmaxf (x, y);
> +}
> +
With -ffinite-math-only -fno-signed-zeros, it does work with
x >= y ? x : y
while without `-ffinite-math-only -fno-signed-zeros`, it cannot.
@Xi Ruoyao Is it expected by IEEE?
And `fmaxf` is also expanded to fmax.
#include <math.h>
float x (float a1, float a2) {
return fmaxf (a1, a2);
}
I think that we should add such a testcase.
> --
> 2.43.0
On Tue, 2024-03-26 at 11:15 +0800, YunQiang Su wrote:
/* snip */
> With -ffinite-math-only -fno-signed-zeros, it does work with
> x >= y ? x : y
> while without `-ffinite-math-only -fno-signed-zeros`, it cannot.
> @Xi Ruoyao Is it expected by IEEE?
When y is (quiet) NaN and x is not, fmax(x, y) should produce x but x >=
y ? x : y should produce y. Thus -ffinite-math-only is needed.
When x is +0.0 and y is -0.0, x >= y ? x : y should produce +0.0 but
fmax(x, y) may produce +0.0 or -0.0 (IEEE allows both and I don't see a
more strict requirement in MIPS 6.06 manual either). Thus -fno-signed-
zeros is needed.
Xi Ruoyao <xry111@xry111.site> 于2024年3月26日周二 18:10写道:
>
> On Tue, 2024-03-26 at 11:15 +0800, YunQiang Su wrote:
>
> /* snip */
>
> > With -ffinite-math-only -fno-signed-zeros, it does work with
> > x >= y ? x : y
> > while without `-ffinite-math-only -fno-signed-zeros`, it cannot.
> > @Xi Ruoyao Is it expected by IEEE?
>
> When y is (quiet) NaN and x is not, fmax(x, y) should produce x but x >=
> y ? x : y should produce y. Thus -ffinite-math-only is needed.
>
> When x is +0.0 and y is -0.0, x >= y ? x : y should produce +0.0 but
> fmax(x, y) may produce +0.0 or -0.0 (IEEE allows both and I don't see a
> more strict requirement in MIPS 6.06 manual either). Thus -fno-signed-
> zeros is needed.
>
Yes, MIPS 6.06 requires `max.f Y,+0,-0` produce +0.
There is a table after the description of max.fmt instruction,
aka Table 4.1 Special Cases for FP MAX, MIN, MAXA, MINA.
> --
> Xi Ruoyao <xry111@xry111.site>
> School of Aerospace Science and Technology, Xidian University
@@ -219,6 +219,12 @@
(eq_attr "type" "fabs,fneg,fmove"))
"i6400_fpu_short, i6400_fpu_apu")
+;; min, max
+(define_insn_reservation "i6400_fpu_minmax" 2
+ (and (eq_attr "cpu" "i6400")
+ (eq_attr "type" "fminmax"))
+ "i6400_fpu_short+i6400_fpu_logic")
+
;; fadd, fsub, fcvt
(define_insn_reservation "i6400_fpu_fadd" 4
(and (eq_attr "cpu" "i6400")
@@ -1259,6 +1259,8 @@ struct mips_cpu_info {
#define ISA_HAS_9BIT_DISPLACEMENT (mips_isa_rev >= 6 \
|| ISA_HAS_MIPS16E2)
+#define ISA_HAS_FMIN_FMAX (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
@@ -97,6 +97,10 @@
UNSPEC_GET_FCSR
UNSPEC_SET_FCSR
+ ;; Floating-point unspecs.
+ UNSPEC_FMIN
+ UNSPEC_FMAX
+
;; HI/LO moves.
UNSPEC_MFHI
UNSPEC_MTHI
@@ -370,6 +374,7 @@
;; frsqrt floating point reciprocal square root
;; frsqrt1 floating point reciprocal square root step1
;; frsqrt2 floating point reciprocal square root step2
+;; fminmax floating point min/max
;; dspmac DSP MAC instructions not saturating the accumulator
;; dspmacsat DSP MAC instructions that saturate the accumulator
;; accext DSP accumulator extract instructions
@@ -387,8 +392,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,dspmac,dspmacsat,accext,accmod,dspalu,dspalusat,
- multi,atomic,syncloop,nop,ghost,multimem,
+ frsqrt,frsqrt1,frsqrt2,fminmax,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,
@@ -7971,6 +7976,47 @@
[(set_attr "move_type" "load")
(set_attr "insn_count" "2")])
+;;
+;; Float point MIN/MAX
+;;
+
+(define_insn "smin<mode>3"
+ [(set (match_operand:SCALARF 0 "register_operand" "=f")
+ (smin:SCALARF (match_operand:SCALARF 1 "register_operand" "f")
+ (match_operand:SCALARF 2 "register_operand" "f")))]
+ "ISA_HAS_FMIN_FMAX"
+ "min.<fmt>\t%0,%1,%2"
+ [(set_attr "type" "fminmax")
+ (set_attr "mode" "<UNITMODE>")])
+
+(define_insn "smax<mode>3"
+ [(set (match_operand:SCALARF 0 "register_operand" "=f")
+ (smax:SCALARF (match_operand:SCALARF 1 "register_operand" "f")
+ (match_operand:SCALARF 2 "register_operand" "f")))]
+ "ISA_HAS_FMIN_FMAX"
+ "max.<fmt>\t%0,%1,%2"
+ [(set_attr "type" "fminmax")
+ (set_attr "mode" "<UNITMODE>")])
+
+(define_insn "fmin<mode>3"
+ [(set (match_operand:SCALARF 0 "register_operand" "=f")
+ (unspec:SCALARF [(use (match_operand:SCALARF 1 "register_operand" "f"))
+ (use (match_operand:SCALARF 2 "register_operand" "f"))]
+ UNSPEC_FMIN))]
+ "ISA_HAS_FMIN_FMAX"
+ "min.<fmt>\t%0,%1,%2"
+ [(set_attr "type" "fminmax")
+ (set_attr "mode" "<UNITMODE>")])
+
+(define_insn "fmax<mode>3"
+ [(set (match_operand:SCALARF 0 "register_operand" "=f")
+ (unspec:SCALARF [(use (match_operand:SCALARF 1 "register_operand" "f"))
+ (use (match_operand:SCALARF 2 "register_operand" "f"))]
+ UNSPEC_FMAX))]
+ "ISA_HAS_FMIN_FMAX"
+ "max.<fmt>\t%0,%1,%2"
+ [(set_attr "type" "fminmax")
+ (set_attr "mode" "<UNITMODE>")])
;; 2 HI loads are joined.
(define_peephole2
@@ -170,7 +170,7 @@
;; fabs, fneg, fcmp
(define_insn_reservation "p6600_fpu_fabs" 2
(and (eq_attr "cpu" "p6600")
- (ior (eq_attr "type" "fabs,fneg,fcmp,fmove")
+ (ior (eq_attr "type" "fabs,fneg,fcmp,fmove,fminmax")
(and (eq_attr "type" "condmove")
(eq_attr "mode" "SF,DF"))))
"p6600_fpu_short, p6600_fpu_apu")
new file mode 100644
@@ -0,0 +1,40 @@
+/* { dg-do compile } */
+/* { dg-options "-mhard-float -fno-finite-math-only -march=mips32r6" } */
+/* { dg-skip-if "code quality test" { *-*-* } { "-O0" } { "" } } */
+
+/* Test MIN.D. */
+
+/* { dg-final { scan-assembler "\tmin\\.d\t" } } */
+double
+test01 (double x, double y)
+{
+ return __builtin_fmin (x, y);
+}
+
+/* Test MIN.S. */
+
+/* { dg-final { scan-assembler "\tmin\\.s\t" } } */
+float
+test02 (float x, float y)
+{
+ return __builtin_fminf (x, y);
+}
+
+/* Test MAX.D. */
+
+/* { dg-final { scan-assembler "\tmax\\.d\t" } } */
+double
+test03 (double x, double y)
+{
+ return __builtin_fmax (x, y);
+}
+
+/* Test MAX.S. */
+
+/* { dg-final { scan-assembler "\tmax\\.s\t" } } */
+float
+test04 (float x, float y)
+{
+ return __builtin_fmaxf (x, y);
+}
+