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 (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); +} + -- 2.43.0