Message ID | 20240325094448.1292735-1-jie.mei@oss.cipunited.com |
---|---|
State | New |
Headers | show |
Series | [v2] MIPS: Add MIN/MAX.fmt instructions support for MIPS R6 | expand |
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
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 (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); +} +