]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
LoongArch: Fix usage of LSX and LASX frint/ftint instructions [PR112578]
authorXi Ruoyao <xry111@xry111.site>
Fri, 17 Nov 2023 20:48:20 +0000 (04:48 +0800)
committerXi Ruoyao <xry111@xry111.site>
Wed, 29 Nov 2023 07:07:08 +0000 (15:07 +0800)
The usage LSX and LASX frint/ftint instructions had some problems:

1. These instructions raises FE_INEXACT, which is not allowed with
   -fno-fp-int-builtin-inexact for most C2x section F.10.6 functions
   (the only exceptions are rint, lrint, and llrint).
2. The "frint" instruction without explicit rounding mode is used for
   roundM2, this is incorrect because roundM2 is defined "rounding
   operand 1 to the *nearest* integer, rounding away from zero in the
   event of a tie".  We actually don't have such an instruction.  Our
   frintrne instruction is roundevenM2 (unfortunately, this is not
   documented).
3. These define_insn's are written in a way not so easy to hack.

So I removed these instructions and created a "simd.md" file, then added
them and the corresponding expanders there.  The advantage of the
simd.md file is we don't need to duplicate the RTL template twice (in
lsx.md and lasx.md).

gcc/ChangeLog:

PR target/112578
* config/loongarch/lsx.md (UNSPEC_LSX_VFTINT_S,
UNSPEC_LSX_VFTINTRNE, UNSPEC_LSX_VFTINTRP,
UNSPEC_LSX_VFTINTRM, UNSPEC_LSX_VFRINTRNE_S,
UNSPEC_LSX_VFRINTRNE_D, UNSPEC_LSX_VFRINTRZ_S,
UNSPEC_LSX_VFRINTRZ_D, UNSPEC_LSX_VFRINTRP_S,
UNSPEC_LSX_VFRINTRP_D, UNSPEC_LSX_VFRINTRM_S,
UNSPEC_LSX_VFRINTRM_D): Remove.
(ILSX, FLSX): Move into ...
(VIMODE): Move into ...
(FRINT_S, FRINT_D): Remove.
(frint_pattern_s, frint_pattern_d, frint_suffix): Remove.
(lsx_vfrint_<flsxfmt>, lsx_vftint_s_<ilsxfmt>_<flsxfmt>,
lsx_vftintrne_w_s, lsx_vftintrne_l_d, lsx_vftintrp_w_s,
lsx_vftintrp_l_d, lsx_vftintrm_w_s, lsx_vftintrm_l_d,
lsx_vfrintrne_s, lsx_vfrintrne_d, lsx_vfrintrz_s,
lsx_vfrintrz_d, lsx_vfrintrp_s, lsx_vfrintrp_d,
lsx_vfrintrm_s, lsx_vfrintrm_d,
<FRINT_S:frint_pattern_s>v4sf2,
<FRINT_D:frint_pattern_d>v2df2, round<mode>2,
fix_trunc<mode>2): Remove.
* config/loongarch/lasx.md: Likewise.
* config/loongarch/simd.md: New file.
(ILSX, ILASX, FLSX, FLASX, VIMODE): ... here.
(IVEC, FVEC): New mode iterators.
(VIMODE): ... here.  Extend it to work for all LSX/LASX vector
modes.
(x, wu, simd_isa, WVEC, vimode, simdfmt, simdifmt_for_f,
elebits): New mode attributes.
(UNSPEC_SIMD_FRINTRP, UNSPEC_SIMD_FRINTRZ, UNSPEC_SIMD_FRINT,
UNSPEC_SIMD_FRINTRM, UNSPEC_SIMD_FRINTRNE): New unspecs.
(SIMD_FRINT): New int iterator.
(simd_frint_rounding, simd_frint_pattern): New int attributes.
(<simd_isa>_<x>vfrint<simd_frint_rounding>_<simdfmt>): New
define_insn template for frint instructions.
(<simd_isa>_<x>vftint<simd_frint_rounding>_<simdifmt_for_f>_<simdfmt>):
Likewise, but for ftint instructions.
(<simd_frint_pattern><mode>2): New define_expand with
flag_fp_int_builtin_inexact checked.
(l<simd_frint_pattern><mode><vimode>2): Likewise.
(ftrunc<mode>2): New define_expand.  It does not require
flag_fp_int_builtin_inexact.
(fix_trunc<mode><vimode>2): New define_insn_and_split.  It does
not require flag_fp_int_builtin_inexact.
(include): Add lsx.md and lasx.md.
* config/loongarch/loongarch.md (include): Include simd.md,
instead of including lsx.md and lasx.md directly.
* config/loongarch/loongarch-builtins.cc
(CODE_FOR_lsx_vftint_w_s, CODE_FOR_lsx_vftint_l_d,
CODE_FOR_lasx_xvftint_w_s, CODE_FOR_lasx_xvftint_l_d):
Remove.

gcc/testsuite/ChangeLog:

PR target/112578
* gcc.target/loongarch/vect-frint.c: New test.
* gcc.target/loongarch/vect-frint-no-inexact.c: New test.
* gcc.target/loongarch/vect-ftint.c: New test.
* gcc.target/loongarch/vect-ftint-no-inexact.c: New test.

gcc/config/loongarch/lasx.md
gcc/config/loongarch/loongarch-builtins.cc
gcc/config/loongarch/loongarch.md
gcc/config/loongarch/lsx.md
gcc/config/loongarch/simd.md [new file with mode: 0644]
gcc/testsuite/gcc.target/loongarch/vect-frint-no-inexact.c [new file with mode: 0644]
gcc/testsuite/gcc.target/loongarch/vect-frint.c [new file with mode: 0644]
gcc/testsuite/gcc.target/loongarch/vect-ftint-no-inexact.c [new file with mode: 0644]
gcc/testsuite/gcc.target/loongarch/vect-ftint.c [new file with mode: 0644]

index 2e11f061202d061d52b038fc55a148d8988a9a75..d4a56c307c4d872e0af3e3e14c7750e095e8a2db 100644 (file)
@@ -53,7 +53,6 @@
   UNSPEC_LASX_XVFCMP_SULT
   UNSPEC_LASX_XVFCMP_SUN
   UNSPEC_LASX_XVFCMP_SUNE
-  UNSPEC_LASX_XVFTINT_S
   UNSPEC_LASX_XVFTINT_U
   UNSPEC_LASX_XVCLO
   UNSPEC_LASX_XVSAT_S
   UNSPEC_LASX_XVEXTRINS
   UNSPEC_LASX_XVMSKLTZ
   UNSPEC_LASX_XVSIGNCOV
-  UNSPEC_LASX_XVFTINTRNE_W_S
-  UNSPEC_LASX_XVFTINTRNE_L_D
-  UNSPEC_LASX_XVFTINTRP_W_S
-  UNSPEC_LASX_XVFTINTRP_L_D
-  UNSPEC_LASX_XVFTINTRM_W_S
-  UNSPEC_LASX_XVFTINTRM_L_D
   UNSPEC_LASX_XVFTINT_W_D
   UNSPEC_LASX_XVFFINT_S_L
   UNSPEC_LASX_XVFTINTRZ_W_D
   UNSPEC_LASX_XVFTINTRML_L_S
   UNSPEC_LASX_XVFTINTRNEL_L_S
   UNSPEC_LASX_XVFTINTRNEH_L_S
-  UNSPEC_LASX_XVFRINTRNE_S
-  UNSPEC_LASX_XVFRINTRNE_D
-  UNSPEC_LASX_XVFRINTRZ_S
-  UNSPEC_LASX_XVFRINTRZ_D
-  UNSPEC_LASX_XVFRINTRP_S
-  UNSPEC_LASX_XVFRINTRP_D
-  UNSPEC_LASX_XVFRINTRM_S
-  UNSPEC_LASX_XVFRINTRM_D
   UNSPEC_LASX_XVREPLVE0_Q
   UNSPEC_LASX_XVPERM_W
   UNSPEC_LASX_XVPERMI_Q
 ;; Only used for copy256_{u,s}.w.
 (define_mode_iterator LASX_W    [V8SI V8SF])
 
-;; Only integer modes in LASX.
-(define_mode_iterator ILASX [V4DI V8SI V16HI V32QI])
-
 ;; As ILASX but excludes V32QI.
 (define_mode_iterator ILASX_DWH [V4DI V8SI V16HI])
 
 ;; Only integer modes smaller than a word.
 (define_mode_iterator ILASX_HB  [V16HI V32QI])
 
-;; Only floating-point modes in LASX.
-(define_mode_iterator FLASX  [V4DF V8SF])
-
 ;; Only used for immediate set shuffle elements instruction.
 (define_mode_iterator LASX_WHB_W [V8SI V16HI V32QI V8SF])
 
    (V16HI "w")
    (V32QI "w")])
 
-(define_int_iterator FRINT256_S [UNSPEC_LASX_XVFRINTRP_S
-                              UNSPEC_LASX_XVFRINTRZ_S
-                              UNSPEC_LASX_XVFRINT
-                              UNSPEC_LASX_XVFRINTRM_S])
-
-(define_int_iterator FRINT256_D [UNSPEC_LASX_XVFRINTRP_D
-                              UNSPEC_LASX_XVFRINTRZ_D
-                              UNSPEC_LASX_XVFRINT
-                              UNSPEC_LASX_XVFRINTRM_D])
-
-(define_int_attr frint256_pattern_s
-  [(UNSPEC_LASX_XVFRINTRP_S  "ceil")
-   (UNSPEC_LASX_XVFRINTRZ_S  "btrunc")
-   (UNSPEC_LASX_XVFRINT             "rint")
-   (UNSPEC_LASX_XVFRINTRM_S  "floor")])
-
-(define_int_attr frint256_pattern_d
-  [(UNSPEC_LASX_XVFRINTRP_D  "ceil")
-   (UNSPEC_LASX_XVFRINTRZ_D  "btrunc")
-   (UNSPEC_LASX_XVFRINT             "rint")
-   (UNSPEC_LASX_XVFRINTRM_D  "floor")])
-
-(define_int_attr frint256_suffix
-  [(UNSPEC_LASX_XVFRINTRP_S  "rp")
-   (UNSPEC_LASX_XVFRINTRP_D  "rp")
-   (UNSPEC_LASX_XVFRINTRZ_S  "rz")
-   (UNSPEC_LASX_XVFRINTRZ_D  "rz")
-   (UNSPEC_LASX_XVFRINT             "")
-   (UNSPEC_LASX_XVFRINTRM_S  "rm")
-   (UNSPEC_LASX_XVFRINTRM_D  "rm")])
-
 (define_expand "vec_init<mode><unitmode>"
   [(match_operand:LASX 0 "register_operand")
    (match_operand:LASX 1 "")]
   [(set_attr "type" "simd_fdiv")
    (set_attr "mode" "<MODE>")])
 
-(define_insn "lasx_xvfrint_<flasxfmt>"
-  [(set (match_operand:FLASX 0 "register_operand" "=f")
-       (unspec:FLASX [(match_operand:FLASX 1 "register_operand" "f")]
-                     UNSPEC_LASX_XVFRINT))]
-  "ISA_HAS_LASX"
-  "xvfrint.<flasxfmt>\t%u0,%u1"
-  [(set_attr "type" "simd_fcvt")
-   (set_attr "mode" "<MODE>")])
-
 (define_insn "lasx_xvfrsqrt_<flasxfmt>"
   [(set (match_operand:FLASX 0 "register_operand" "=f")
        (unspec:FLASX [(match_operand:FLASX 1 "register_operand" "f")]
   [(set_attr "type" "simd_fdiv")
    (set_attr "mode" "<MODE>")])
 
-(define_insn "lasx_xvftint_s_<ilasxfmt>_<flasxfmt>"
-  [(set (match_operand:<VIMODE256> 0 "register_operand" "=f")
-       (unspec:<VIMODE256> [(match_operand:FLASX 1 "register_operand" "f")]
-                           UNSPEC_LASX_XVFTINT_S))]
-  "ISA_HAS_LASX"
-  "xvftint.<ilasxfmt>.<flasxfmt>\t%u0,%u1"
-  [(set_attr "type" "simd_fcvt")
-   (set_attr "cnv_mode" "<FINTCNV256_2>")
-   (set_attr "mode" "<MODE>")])
-
 (define_insn "lasx_xvftint_u_<ilasxfmt_u>_<flasxfmt>"
   [(set (match_operand:<VIMODE256> 0 "register_operand" "=f")
        (unspec:<VIMODE256> [(match_operand:FLASX 1 "register_operand" "f")]
    (set_attr "cnv_mode" "<FINTCNV256_2>")
    (set_attr "mode" "<MODE>")])
 
-
-
-(define_insn "fix_trunc<FLASX:mode><mode256_i>2"
-  [(set (match_operand:<VIMODE256> 0 "register_operand" "=f")
-       (fix:<VIMODE256> (match_operand:FLASX 1 "register_operand" "f")))]
-  "ISA_HAS_LASX"
-  "xvftintrz.<ilasxfmt>.<flasxfmt>\t%u0,%u1"
-  [(set_attr "type" "simd_fcvt")
-   (set_attr "cnv_mode" "<FINTCNV256_2>")
-   (set_attr "mode" "<MODE>")])
-
-
 (define_insn "fixuns_trunc<FLASX:mode><mode256_i>2"
   [(set (match_operand:<VIMODE256> 0 "register_operand" "=f")
        (unsigned_fix:<VIMODE256> (match_operand:FLASX 1 "register_operand" "f")))]
   [(set_attr "type" "simd_fmadd")
    (set_attr "mode" "<MODE>")])
 
-(define_insn "lasx_xvftintrne_w_s"
-  [(set (match_operand:V8SI 0 "register_operand" "=f")
-       (unspec:V8SI [(match_operand:V8SF 1 "register_operand" "f")]
-                    UNSPEC_LASX_XVFTINTRNE_W_S))]
-  "ISA_HAS_LASX"
-  "xvftintrne.w.s\t%u0,%u1"
-  [(set_attr "type" "simd_shift")
-   (set_attr "mode" "V8SF")])
-
-(define_insn "lasx_xvftintrne_l_d"
-  [(set (match_operand:V4DI 0 "register_operand" "=f")
-       (unspec:V4DI [(match_operand:V4DF 1 "register_operand" "f")]
-                    UNSPEC_LASX_XVFTINTRNE_L_D))]
-  "ISA_HAS_LASX"
-  "xvftintrne.l.d\t%u0,%u1"
-  [(set_attr "type" "simd_shift")
-   (set_attr "mode" "V4DF")])
-
-(define_insn "lasx_xvftintrp_w_s"
-  [(set (match_operand:V8SI 0 "register_operand" "=f")
-       (unspec:V8SI [(match_operand:V8SF 1 "register_operand" "f")]
-                    UNSPEC_LASX_XVFTINTRP_W_S))]
-  "ISA_HAS_LASX"
-  "xvftintrp.w.s\t%u0,%u1"
-  [(set_attr "type" "simd_shift")
-   (set_attr "mode" "V8SF")])
-
-(define_insn "lasx_xvftintrp_l_d"
-  [(set (match_operand:V4DI 0 "register_operand" "=f")
-       (unspec:V4DI [(match_operand:V4DF 1 "register_operand" "f")]
-                    UNSPEC_LASX_XVFTINTRP_L_D))]
-  "ISA_HAS_LASX"
-  "xvftintrp.l.d\t%u0,%u1"
-  [(set_attr "type" "simd_shift")
-   (set_attr "mode" "V4DF")])
-
-(define_insn "lasx_xvftintrm_w_s"
-  [(set (match_operand:V8SI 0 "register_operand" "=f")
-       (unspec:V8SI [(match_operand:V8SF 1 "register_operand" "f")]
-                    UNSPEC_LASX_XVFTINTRM_W_S))]
-  "ISA_HAS_LASX"
-  "xvftintrm.w.s\t%u0,%u1"
-  [(set_attr "type" "simd_shift")
-   (set_attr "mode" "V8SF")])
-
-(define_insn "lasx_xvftintrm_l_d"
-  [(set (match_operand:V4DI 0 "register_operand" "=f")
-       (unspec:V4DI [(match_operand:V4DF 1 "register_operand" "f")]
-                    UNSPEC_LASX_XVFTINTRM_L_D))]
-  "ISA_HAS_LASX"
-  "xvftintrm.l.d\t%u0,%u1"
-  [(set_attr "type" "simd_shift")
-   (set_attr "mode" "V4DF")])
-
 (define_insn "lasx_xvftint_w_d"
   [(set (match_operand:V8SI 0 "register_operand" "=f")
        (unspec:V8SI [(match_operand:V4DF 1 "register_operand" "f")
   [(set_attr "type" "simd_shift")
    (set_attr "mode" "V8SF")])
 
-(define_insn "lasx_xvfrintrne_s"
-  [(set (match_operand:V8SF 0 "register_operand" "=f")
-       (unspec:V8SF [(match_operand:V8SF 1 "register_operand" "f")]
-                    UNSPEC_LASX_XVFRINTRNE_S))]
-  "ISA_HAS_LASX"
-  "xvfrintrne.s\t%u0,%u1"
-  [(set_attr "type" "simd_shift")
-   (set_attr "mode" "V8SF")])
-
-(define_insn "lasx_xvfrintrne_d"
-  [(set (match_operand:V4DF 0 "register_operand" "=f")
-       (unspec:V4DF [(match_operand:V4DF 1 "register_operand" "f")]
-                    UNSPEC_LASX_XVFRINTRNE_D))]
-  "ISA_HAS_LASX"
-  "xvfrintrne.d\t%u0,%u1"
-  [(set_attr "type" "simd_shift")
-   (set_attr "mode" "V4DF")])
-
-(define_insn "lasx_xvfrintrz_s"
-  [(set (match_operand:V8SF 0 "register_operand" "=f")
-       (unspec:V8SF [(match_operand:V8SF 1 "register_operand" "f")]
-                    UNSPEC_LASX_XVFRINTRZ_S))]
-  "ISA_HAS_LASX"
-  "xvfrintrz.s\t%u0,%u1"
-  [(set_attr "type" "simd_shift")
-   (set_attr "mode" "V8SF")])
-
-(define_insn "lasx_xvfrintrz_d"
-  [(set (match_operand:V4DF 0 "register_operand" "=f")
-       (unspec:V4DF [(match_operand:V4DF 1 "register_operand" "f")]
-                    UNSPEC_LASX_XVFRINTRZ_D))]
-  "ISA_HAS_LASX"
-  "xvfrintrz.d\t%u0,%u1"
-  [(set_attr "type" "simd_shift")
-   (set_attr "mode" "V4DF")])
-
-(define_insn "lasx_xvfrintrp_s"
-  [(set (match_operand:V8SF 0 "register_operand" "=f")
-       (unspec:V8SF [(match_operand:V8SF 1 "register_operand" "f")]
-                    UNSPEC_LASX_XVFRINTRP_S))]
-  "ISA_HAS_LASX"
-  "xvfrintrp.s\t%u0,%u1"
-  [(set_attr "type" "simd_shift")
-   (set_attr "mode" "V8SF")])
-
-(define_insn "lasx_xvfrintrp_d"
-  [(set (match_operand:V4DF 0 "register_operand" "=f")
-       (unspec:V4DF [(match_operand:V4DF 1 "register_operand" "f")]
-                    UNSPEC_LASX_XVFRINTRP_D))]
-  "ISA_HAS_LASX"
-  "xvfrintrp.d\t%u0,%u1"
-  [(set_attr "type" "simd_shift")
-   (set_attr "mode" "V4DF")])
-
-(define_insn "lasx_xvfrintrm_s"
-  [(set (match_operand:V8SF 0 "register_operand" "=f")
-       (unspec:V8SF [(match_operand:V8SF 1 "register_operand" "f")]
-                    UNSPEC_LASX_XVFRINTRM_S))]
-  "ISA_HAS_LASX"
-  "xvfrintrm.s\t%u0,%u1"
-  [(set_attr "type" "simd_shift")
-   (set_attr "mode" "V8SF")])
-
-(define_insn "lasx_xvfrintrm_d"
-  [(set (match_operand:V4DF 0 "register_operand" "=f")
-       (unspec:V4DF [(match_operand:V4DF 1 "register_operand" "f")]
-                    UNSPEC_LASX_XVFRINTRM_D))]
-  "ISA_HAS_LASX"
-  "xvfrintrm.d\t%u0,%u1"
-  [(set_attr "type" "simd_shift")
-   (set_attr "mode" "V4DF")])
-
-;; Vector versions of the floating-point frint patterns.
-;; Expands to btrunc, ceil, floor, rint.
-(define_insn "<FRINT256_S:frint256_pattern_s>v8sf2"
- [(set (match_operand:V8SF 0 "register_operand" "=f")
-       (unspec:V8SF [(match_operand:V8SF 1 "register_operand" "f")]
-                        FRINT256_S))]
-  "ISA_HAS_LASX"
-  "xvfrint<FRINT256_S:frint256_suffix>.s\t%u0,%u1"
-  [(set_attr "type" "simd_shift")
-   (set_attr "mode" "V8SF")])
-
-(define_insn "<FRINT256_D:frint256_pattern_d>v4df2"
- [(set (match_operand:V4DF 0 "register_operand" "=f")
-       (unspec:V4DF [(match_operand:V4DF 1 "register_operand" "f")]
-                        FRINT256_D))]
-  "ISA_HAS_LASX"
-  "xvfrint<FRINT256_D:frint256_suffix>.d\t%u0,%u1"
-  [(set_attr "type" "simd_shift")
-   (set_attr "mode" "V4DF")])
-
-;; Expands to round.
-(define_insn "round<mode>2"
- [(set (match_operand:FLASX 0 "register_operand" "=f")
-       (unspec:FLASX [(match_operand:FLASX 1 "register_operand" "f")]
-                        UNSPEC_LASX_XVFRINT))]
-  "ISA_HAS_LASX"
-  "xvfrint.<flasxfmt>\t%u0,%u1"
-  [(set_attr "type" "simd_shift")
-   (set_attr "mode" "<MODE>")])
-
 ;; Offset load and broadcast
 (define_expand "lasx_xvldrepl_<lasxfmt_f>"
   [(match_operand:LASX 0 "register_operand")
index db02aacdc3f432fdc6b27d12bde1d62468b4cd9f..cbd833aa283e832c8eecdb26432202cf80332fd9 100644 (file)
@@ -419,8 +419,6 @@ AVAIL_ALL (lasx, ISA_HAS_LASX)
 #define CODE_FOR_lsx_vabsd_hu CODE_FOR_lsx_vabsd_u_hu
 #define CODE_FOR_lsx_vabsd_wu CODE_FOR_lsx_vabsd_u_wu
 #define CODE_FOR_lsx_vabsd_du CODE_FOR_lsx_vabsd_u_du
-#define CODE_FOR_lsx_vftint_w_s CODE_FOR_lsx_vftint_s_w_s
-#define CODE_FOR_lsx_vftint_l_d CODE_FOR_lsx_vftint_s_l_d
 #define CODE_FOR_lsx_vftint_wu_s CODE_FOR_lsx_vftint_u_wu_s
 #define CODE_FOR_lsx_vftint_lu_d CODE_FOR_lsx_vftint_u_lu_d
 #define CODE_FOR_lsx_vandn_v CODE_FOR_vandnv16qi3
@@ -725,8 +723,6 @@ AVAIL_ALL (lasx, ISA_HAS_LASX)
 #define CODE_FOR_lasx_xvssrlrn_bu_h CODE_FOR_lasx_xvssrlrn_u_bu_h
 #define CODE_FOR_lasx_xvssrlrn_hu_w CODE_FOR_lasx_xvssrlrn_u_hu_w
 #define CODE_FOR_lasx_xvssrlrn_wu_d CODE_FOR_lasx_xvssrlrn_u_wu_d
-#define CODE_FOR_lasx_xvftint_w_s CODE_FOR_lasx_xvftint_s_w_s
-#define CODE_FOR_lasx_xvftint_l_d CODE_FOR_lasx_xvftint_s_l_d
 #define CODE_FOR_lasx_xvftint_wu_s CODE_FOR_lasx_xvftint_u_wu_s
 #define CODE_FOR_lasx_xvftint_lu_d CODE_FOR_lasx_xvftint_u_lu_d
 #define CODE_FOR_lasx_xvsllwil_h_b CODE_FOR_lasx_xvsllwil_s_h_b
index cd4ed495697e50ec7d491414ab68ac92a089f56e..78ed63f213260f81a6adce0ecb8955fc4a5861a5 100644 (file)
 (include "generic.md")
 (include "la464.md")
 
-; The LoongArch SX Instructions.
-(include "lsx.md")
-
-; The LoongArch ASX Instructions.
-(include "lasx.md")
+; The LoongArch SIMD Instructions.
+(include "simd.md")
 
 (define_c_enum "unspec" [
   UNSPEC_ADDRESS_FIRST
index 5e8d8d74b43b19ec3a78be9e3848e16bb0e808f7..c1c3719e383f3cac79c8d3ce0f0227a5163c41fa 100644 (file)
@@ -55,7 +55,6 @@
   UNSPEC_LSX_VFCMP_SULT
   UNSPEC_LSX_VFCMP_SUN
   UNSPEC_LSX_VFCMP_SUNE
-  UNSPEC_LSX_VFTINT_S
   UNSPEC_LSX_VFTINT_U
   UNSPEC_LSX_VSAT_S
   UNSPEC_LSX_VSAT_U
@@ -89,9 +88,6 @@
   UNSPEC_LSX_VEXTRINS
   UNSPEC_LSX_VMSKLTZ
   UNSPEC_LSX_VSIGNCOV
-  UNSPEC_LSX_VFTINTRNE
-  UNSPEC_LSX_VFTINTRP
-  UNSPEC_LSX_VFTINTRM
   UNSPEC_LSX_VFTINT_W_D
   UNSPEC_LSX_VFFINT_S_L
   UNSPEC_LSX_VFTINTRZ_W_D
   UNSPEC_LSX_VFTINTRNEL_L_S
   UNSPEC_LSX_VFTINTRNEH_L_S
   UNSPEC_LSX_VFTINTH_L_H
-  UNSPEC_LSX_VFRINTRNE_S
-  UNSPEC_LSX_VFRINTRNE_D
-  UNSPEC_LSX_VFRINTRZ_S
-  UNSPEC_LSX_VFRINTRZ_D
-  UNSPEC_LSX_VFRINTRP_S
-  UNSPEC_LSX_VFRINTRP_D
-  UNSPEC_LSX_VFRINTRM_S
-  UNSPEC_LSX_VFRINTRM_D
   UNSPEC_LSX_VSSRARN_S
   UNSPEC_LSX_VSSRARN_U
   UNSPEC_LSX_VSSRLN_U
 ;; Only used for copy_{u,s}.w and vilvh.
 (define_mode_iterator LSX_W    [V4SI V4SF])
 
-;; Only integer modes.
-(define_mode_iterator ILSX     [V2DI V4SI V8HI V16QI])
-
 ;; As ILSX but excludes V16QI.
 (define_mode_iterator ILSX_DWH [V2DI V4SI V8HI])
 
 ;;;; Only integer modes for fixed-point madd_q/maddr_q.
 ;;(define_mode_iterator ILSX_WH  [V4SI V8HI])
 
-;; Only floating-point modes.
-(define_mode_iterator FLSX     [V2DF V4SF])
-
 ;; Only used for immediate set shuffle elements instruction.
 (define_mode_iterator LSX_WHB_W [V4SI V8HI V16QI V4SF])
 
-;; The attribute gives the integer vector mode with same size.
-(define_mode_attr VIMODE
-  [(V2DF "V2DI")
-   (V4SF "V4SI")
-   (V2DI "V2DI")
-   (V4SI "V4SI")
-   (V8HI "V8HI")
-   (V16QI "V16QI")])
-
 ;; The attribute gives half modes for vector modes.
 (define_mode_attr VHMODE
   [(V8HI "V16QI")
    (V4SI  "uimm5")
    (V2DI  "uimm6")])
 
-
-(define_int_iterator FRINT_S [UNSPEC_LSX_VFRINTRP_S
-                           UNSPEC_LSX_VFRINTRZ_S
-                           UNSPEC_LSX_VFRINT
-                           UNSPEC_LSX_VFRINTRM_S])
-
-(define_int_iterator FRINT_D [UNSPEC_LSX_VFRINTRP_D
-                           UNSPEC_LSX_VFRINTRZ_D
-                           UNSPEC_LSX_VFRINT
-                           UNSPEC_LSX_VFRINTRM_D])
-
-(define_int_attr frint_pattern_s
-  [(UNSPEC_LSX_VFRINTRP_S  "ceil")
-   (UNSPEC_LSX_VFRINTRZ_S  "btrunc")
-   (UNSPEC_LSX_VFRINT     "rint")
-   (UNSPEC_LSX_VFRINTRM_S  "floor")])
-
-(define_int_attr frint_pattern_d
-  [(UNSPEC_LSX_VFRINTRP_D  "ceil")
-   (UNSPEC_LSX_VFRINTRZ_D  "btrunc")
-   (UNSPEC_LSX_VFRINT     "rint")
-   (UNSPEC_LSX_VFRINTRM_D  "floor")])
-
-(define_int_attr frint_suffix
-  [(UNSPEC_LSX_VFRINTRP_S  "rp")
-   (UNSPEC_LSX_VFRINTRP_D  "rp")
-   (UNSPEC_LSX_VFRINTRZ_S  "rz")
-   (UNSPEC_LSX_VFRINTRZ_D  "rz")
-   (UNSPEC_LSX_VFRINT     "")
-   (UNSPEC_LSX_VFRINTRM_S  "rm")
-   (UNSPEC_LSX_VFRINTRM_D  "rm")])
-
 (define_expand "vec_init<mode><unitmode>"
   [(match_operand:LSX 0 "register_operand")
    (match_operand:LSX 1 "")]
   [(set_attr "type" "simd_fdiv")
    (set_attr "mode" "<MODE>")])
 
-(define_insn "lsx_vfrint_<flsxfmt>"
-  [(set (match_operand:FLSX 0 "register_operand" "=f")
-       (unspec:FLSX [(match_operand:FLSX 1 "register_operand" "f")]
-                    UNSPEC_LSX_VFRINT))]
-  "ISA_HAS_LSX"
-  "vfrint.<flsxfmt>\t%w0,%w1"
-  [(set_attr "type" "simd_fcvt")
-   (set_attr "mode" "<MODE>")])
-
 (define_insn "lsx_vfrsqrt_<flsxfmt>"
   [(set (match_operand:FLSX 0 "register_operand" "=f")
        (unspec:FLSX [(match_operand:FLSX 1 "register_operand" "f")]
   [(set_attr "type" "simd_fdiv")
    (set_attr "mode" "<MODE>")])
 
-(define_insn "lsx_vftint_s_<ilsxfmt>_<flsxfmt>"
-  [(set (match_operand:<VIMODE> 0 "register_operand" "=f")
-       (unspec:<VIMODE> [(match_operand:FLSX 1 "register_operand" "f")]
-                        UNSPEC_LSX_VFTINT_S))]
-  "ISA_HAS_LSX"
-  "vftint.<ilsxfmt>.<flsxfmt>\t%w0,%w1"
-  [(set_attr "type" "simd_fcvt")
-   (set_attr "cnv_mode" "<FINTCNV_2>")
-   (set_attr "mode" "<MODE>")])
-
 (define_insn "lsx_vftint_u_<ilsxfmt_u>_<flsxfmt>"
   [(set (match_operand:<VIMODE> 0 "register_operand" "=f")
        (unspec:<VIMODE> [(match_operand:FLSX 1 "register_operand" "f")]
    (set_attr "cnv_mode" "<FINTCNV_2>")
    (set_attr "mode" "<MODE>")])
 
-(define_insn "fix_trunc<FLSX:mode><mode_i>2"
-  [(set (match_operand:<VIMODE> 0 "register_operand" "=f")
-       (fix:<VIMODE> (match_operand:FLSX 1 "register_operand" "f")))]
-  "ISA_HAS_LSX"
-  "vftintrz.<ilsxfmt>.<flsxfmt>\t%w0,%w1"
-  [(set_attr "type" "simd_fcvt")
-   (set_attr "cnv_mode" "<FINTCNV_2>")
-   (set_attr "mode" "<MODE>")])
-
 (define_insn "fixuns_trunc<FLSX:mode><mode_i>2"
   [(set (match_operand:<VIMODE> 0 "register_operand" "=f")
        (unsigned_fix:<VIMODE> (match_operand:FLSX 1 "register_operand" "f")))]
   [(set_attr "type" "simd_fmadd")
    (set_attr "mode" "<MODE>")])
 
-(define_insn "lsx_vftintrne_w_s"
-  [(set (match_operand:V4SI 0 "register_operand" "=f")
-       (unspec:V4SI [(match_operand:V4SF 1 "register_operand" "f")]
-                    UNSPEC_LSX_VFTINTRNE))]
-  "ISA_HAS_LSX"
-  "vftintrne.w.s\t%w0,%w1"
-  [(set_attr "type" "simd_shift")
-   (set_attr "mode" "V4SF")])
-
-(define_insn "lsx_vftintrne_l_d"
-  [(set (match_operand:V2DI 0 "register_operand" "=f")
-       (unspec:V2DI [(match_operand:V2DF 1 "register_operand" "f")]
-                    UNSPEC_LSX_VFTINTRNE))]
-  "ISA_HAS_LSX"
-  "vftintrne.l.d\t%w0,%w1"
-  [(set_attr "type" "simd_shift")
-   (set_attr "mode" "V2DF")])
-
-(define_insn "lsx_vftintrp_w_s"
-  [(set (match_operand:V4SI 0 "register_operand" "=f")
-       (unspec:V4SI [(match_operand:V4SF 1 "register_operand" "f")]
-                    UNSPEC_LSX_VFTINTRP))]
-  "ISA_HAS_LSX"
-  "vftintrp.w.s\t%w0,%w1"
-  [(set_attr "type" "simd_shift")
-   (set_attr "mode" "V4SF")])
-
-(define_insn "lsx_vftintrp_l_d"
-  [(set (match_operand:V2DI 0 "register_operand" "=f")
-       (unspec:V2DI [(match_operand:V2DF 1 "register_operand" "f")]
-                    UNSPEC_LSX_VFTINTRP))]
-  "ISA_HAS_LSX"
-  "vftintrp.l.d\t%w0,%w1"
-  [(set_attr "type" "simd_shift")
-   (set_attr "mode" "V2DF")])
-
-(define_insn "lsx_vftintrm_w_s"
-  [(set (match_operand:V4SI 0 "register_operand" "=f")
-       (unspec:V4SI [(match_operand:V4SF 1 "register_operand" "f")]
-                    UNSPEC_LSX_VFTINTRM))]
-  "ISA_HAS_LSX"
-  "vftintrm.w.s\t%w0,%w1"
-  [(set_attr "type" "simd_shift")
-   (set_attr "mode" "V4SF")])
-
-(define_insn "lsx_vftintrm_l_d"
-  [(set (match_operand:V2DI 0 "register_operand" "=f")
-       (unspec:V2DI [(match_operand:V2DF 1 "register_operand" "f")]
-                    UNSPEC_LSX_VFTINTRM))]
-  "ISA_HAS_LSX"
-  "vftintrm.l.d\t%w0,%w1"
-  [(set_attr "type" "simd_shift")
-   (set_attr "mode" "V2DF")])
-
 (define_insn "lsx_vftint_w_d"
   [(set (match_operand:V4SI 0 "register_operand" "=f")
        (unspec:V4SI [(match_operand:V2DF 1 "register_operand" "f")
   [(set_attr "type" "simd_shift")
    (set_attr "mode" "V4SF")])
 
-(define_insn "lsx_vfrintrne_s"
-  [(set (match_operand:V4SF 0 "register_operand" "=f")
-       (unspec:V4SF [(match_operand:V4SF 1 "register_operand" "f")]
-                    UNSPEC_LSX_VFRINTRNE_S))]
-  "ISA_HAS_LSX"
-  "vfrintrne.s\t%w0,%w1"
-  [(set_attr "type" "simd_shift")
-   (set_attr "mode" "V4SF")])
-
-(define_insn "lsx_vfrintrne_d"
-  [(set (match_operand:V2DF 0 "register_operand" "=f")
-       (unspec:V2DF [(match_operand:V2DF 1 "register_operand" "f")]
-                    UNSPEC_LSX_VFRINTRNE_D))]
-  "ISA_HAS_LSX"
-  "vfrintrne.d\t%w0,%w1"
-  [(set_attr "type" "simd_shift")
-   (set_attr "mode" "V2DF")])
-
-(define_insn "lsx_vfrintrz_s"
-  [(set (match_operand:V4SF 0 "register_operand" "=f")
-       (unspec:V4SF [(match_operand:V4SF 1 "register_operand" "f")]
-                    UNSPEC_LSX_VFRINTRZ_S))]
-  "ISA_HAS_LSX"
-  "vfrintrz.s\t%w0,%w1"
-  [(set_attr "type" "simd_shift")
-   (set_attr "mode" "V4SF")])
-
-(define_insn "lsx_vfrintrz_d"
-  [(set (match_operand:V2DF 0 "register_operand" "=f")
-       (unspec:V2DF [(match_operand:V2DF 1 "register_operand" "f")]
-                    UNSPEC_LSX_VFRINTRZ_D))]
-  "ISA_HAS_LSX"
-  "vfrintrz.d\t%w0,%w1"
-  [(set_attr "type" "simd_shift")
-   (set_attr "mode" "V2DF")])
-
-(define_insn "lsx_vfrintrp_s"
-  [(set (match_operand:V4SF 0 "register_operand" "=f")
-       (unspec:V4SF [(match_operand:V4SF 1 "register_operand" "f")]
-                    UNSPEC_LSX_VFRINTRP_S))]
-  "ISA_HAS_LSX"
-  "vfrintrp.s\t%w0,%w1"
-  [(set_attr "type" "simd_shift")
-   (set_attr "mode" "V4SF")])
-
-(define_insn "lsx_vfrintrp_d"
-  [(set (match_operand:V2DF 0 "register_operand" "=f")
-       (unspec:V2DF [(match_operand:V2DF 1 "register_operand" "f")]
-                    UNSPEC_LSX_VFRINTRP_D))]
-  "ISA_HAS_LSX"
-  "vfrintrp.d\t%w0,%w1"
-  [(set_attr "type" "simd_shift")
-   (set_attr "mode" "V2DF")])
-
-(define_insn "lsx_vfrintrm_s"
-  [(set (match_operand:V4SF 0 "register_operand" "=f")
-       (unspec:V4SF [(match_operand:V4SF 1 "register_operand" "f")]
-                    UNSPEC_LSX_VFRINTRM_S))]
-  "ISA_HAS_LSX"
-  "vfrintrm.s\t%w0,%w1"
-  [(set_attr "type" "simd_shift")
-   (set_attr "mode" "V4SF")])
-
-(define_insn "lsx_vfrintrm_d"
-  [(set (match_operand:V2DF 0 "register_operand" "=f")
-       (unspec:V2DF [(match_operand:V2DF 1 "register_operand" "f")]
-                    UNSPEC_LSX_VFRINTRM_D))]
-  "ISA_HAS_LSX"
-  "vfrintrm.d\t%w0,%w1"
-  [(set_attr "type" "simd_shift")
-   (set_attr "mode" "V2DF")])
-
-;; Vector versions of the floating-point frint patterns.
-;; Expands to btrunc, ceil, floor, rint.
-(define_insn "<FRINT_S:frint_pattern_s>v4sf2"
- [(set (match_operand:V4SF 0 "register_operand" "=f")
-       (unspec:V4SF [(match_operand:V4SF 1 "register_operand" "f")]
-                        FRINT_S))]
-  "ISA_HAS_LSX"
-  "vfrint<FRINT_S:frint_suffix>.s\t%w0,%w1"
-  [(set_attr "type" "simd_shift")
-   (set_attr "mode" "V4SF")])
-
-(define_insn "<FRINT_D:frint_pattern_d>v2df2"
- [(set (match_operand:V2DF 0 "register_operand" "=f")
-       (unspec:V2DF [(match_operand:V2DF 1 "register_operand" "f")]
-                        FRINT_D))]
-  "ISA_HAS_LSX"
-  "vfrint<FRINT_D:frint_suffix>.d\t%w0,%w1"
-  [(set_attr "type" "simd_shift")
-   (set_attr "mode" "V2DF")])
-
-;; Expands to round.
-(define_insn "round<mode>2"
- [(set (match_operand:FLSX 0 "register_operand" "=f")
-       (unspec:FLSX [(match_operand:FLSX 1 "register_operand" "f")]
-                        UNSPEC_LSX_VFRINT))]
-  "ISA_HAS_LSX"
-  "vfrint.<flsxfrint>\t%w0,%w1"
-  [(set_attr "type" "simd_shift")
-   (set_attr "mode" "<MODE>")])
-
 ;; Offset load and broadcast
 (define_expand "lsx_vldrepl_<lsxfmt_f>"
   [(match_operand:LSX 0 "register_operand")
diff --git a/gcc/config/loongarch/simd.md b/gcc/config/loongarch/simd.md
new file mode 100644 (file)
index 0000000..27d1ffe
--- /dev/null
@@ -0,0 +1,213 @@
+;; Machine Description for LoongArch SIMD instructions for GNU compiler.
+;; Copyright (C) 2023 Free Software Foundation, Inc.
+
+;; This file is part of GCC.
+
+;; GCC is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3, or (at your option)
+;; any later version.
+
+;; GCC is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GCC; see the file COPYING3.  If not see
+;; <http://www.gnu.org/licenses/>.
+
+;; Integer modes supported by LSX.
+(define_mode_iterator ILSX    [V2DI V4SI V8HI V16QI])
+
+;; Integer modes supported by LASX.
+(define_mode_iterator ILASX   [V4DI V8SI V16HI V32QI])
+
+;; FP modes supported by LSX
+(define_mode_iterator FLSX    [V2DF V4SF])
+
+;; FP modes supported by LASX
+(define_mode_iterator FLASX   [V4DF V8SF])
+
+;; All integer modes available
+(define_mode_iterator IVEC    [(ILSX "ISA_HAS_LSX") (ILASX "ISA_HAS_LASX")])
+
+;; All FP modes available
+(define_mode_iterator FVEC    [(FLSX "ISA_HAS_LSX") (FLASX "ISA_HAS_LASX")])
+
+;; Mnemonic prefix, "x" for LASX modes.
+(define_mode_attr x [(V2DI "") (V4SI "") (V8HI "") (V16QI "")
+                    (V2DF "") (V4SF "")
+                    (V4DI "x") (V8SI "x") (V16HI "x") (V32QI "x")
+                    (V4DF "x") (V8SF "x")])
+
+;; Modifier for vector register, "w" for LSX modes, "u" for LASX modes.
+(define_mode_attr wu [(V2DI "w") (V4SI "w") (V8HI "w") (V16QI "w")
+                     (V2DF "w") (V4SF "w")
+                     (V4DI "u") (V8SI "u") (V16HI "u") (V32QI "u")
+                     (V4DF "u") (V8SF "u")])
+
+;; define_insn name prefix, "lsx" or "lasx"
+(define_mode_attr simd_isa
+  [(V2DI "lsx") (V4SI "lsx") (V8HI "lsx") (V16QI "lsx")
+   (V2DF "lsx") (V4SF "lsx")
+   (V4DI "lasx") (V8SI "lasx") (V16HI "lasx") (V32QI "lasx")
+   (V4DF "lasx") (V8SF "lasx")])
+
+;; Widen integer modes for intermediate values in RTX pattern.
+(define_mode_attr WVEC [(V2DI "V2TI") (V4DI "V4TI")
+                       (V4SI "V4DI") (V8SI "V8DI")
+                       (V8HI "V8SI") (V16HI "V16SI")
+                       (V16QI "V16HI") (V32QI "V32HI")])
+
+;; Integer vector modes with the same length and unit size as a mode.
+(define_mode_attr VIMODE [(V2DI "V2DI") (V4SI "V4SI")
+                         (V8HI "V8HI") (V16QI "V16QI")
+                         (V2DF "V2DI") (V4SF "V4SI")
+                         (V4DI "V4DI") (V8SI "V8SI")
+                         (V16HI "V16HI") (V32QI "V32QI")
+                         (V4DF "V4DI") (V8SF "V8SI")])
+
+;; Lower-case version.
+(define_mode_attr vimode [(V2DF "v2di") (V4SF "v4si")
+                         (V4DF "v4di") (V8SF "v8si")])
+
+;; Suffix for LSX or LASX instructions.
+(define_mode_attr simdfmt [(V2DF "d") (V4DF "d")
+                          (V4SF "s") (V8SF "s")
+                          (V2DI "d") (V4DI "d")
+                          (V4SI "w") (V8SI "w")
+                          (V8HI "h") (V16HI "h")
+                          (V16QI "b") (V32QI "b")])
+
+;; Suffix for integer mode in LSX or LASX instructions with FP input but
+;; integer output.
+(define_mode_attr simdifmt_for_f [(V2DF "l") (V4DF "l")
+                                 (V4SF "w") (V8SF "w")])
+
+;; Size of vector elements in bits.
+(define_mode_attr elmbits [(V2DI "64") (V4DI "64")
+                          (V4SI "32") (V8SI "32")
+                          (V8HI "16") (V16HI "16")
+                          (V16QI "8") (V32QI "8")])
+
+;; =======================================================================
+;; For many LASX instructions, the only difference of it from the LSX
+;; counterpart is the length of vector operands.  Describe these LSX/LASX
+;; instruction here so we can avoid duplicating logics.
+;; =======================================================================
+
+;;
+;; FP vector rounding instructions
+;;
+
+(define_c_enum "unspec"
+  [UNSPEC_SIMD_FRINTRP
+   UNSPEC_SIMD_FRINTRZ
+   UNSPEC_SIMD_FRINT
+   UNSPEC_SIMD_FRINTRM
+   UNSPEC_SIMD_FRINTRNE])
+
+(define_int_iterator SIMD_FRINT
+  [UNSPEC_SIMD_FRINTRP
+   UNSPEC_SIMD_FRINTRZ
+   UNSPEC_SIMD_FRINT
+   UNSPEC_SIMD_FRINTRM
+   UNSPEC_SIMD_FRINTRNE])
+
+(define_int_attr simd_frint_rounding
+  [(UNSPEC_SIMD_FRINTRP                "rp")
+   (UNSPEC_SIMD_FRINTRZ                "rz")
+   (UNSPEC_SIMD_FRINT          "")
+   (UNSPEC_SIMD_FRINTRM                "rm")
+   (UNSPEC_SIMD_FRINTRNE       "rne")])
+
+;; All these, but rint, are controlled by -ffp-int-builtin-inexact.
+;; Note: nearbyint is NOT allowed to raise FE_INEXACT even if
+;; -ffp-int-builtin-inexact, but rint is ALLOWED to raise it even if
+;; -fno-fp-int-builtin-inexact.
+(define_int_attr simd_frint_pattern
+  [(UNSPEC_SIMD_FRINTRP                "ceil")
+   (UNSPEC_SIMD_FRINTRZ                "btrunc")
+   (UNSPEC_SIMD_FRINT          "rint")
+   (UNSPEC_SIMD_FRINTRNE       "roundeven")
+   (UNSPEC_SIMD_FRINTRM                "floor")])
+
+;; <x>vfrint.{/rp/rz/rm}
+(define_insn "<simd_isa>_<x>vfrint<simd_frint_rounding>_<simdfmt>"
+  [(set (match_operand:FVEC 0 "register_operand" "=f")
+       (unspec:FVEC [(match_operand:FVEC 1 "register_operand" "f")]
+                    SIMD_FRINT))]
+  ""
+  "<x>vfrint<simd_frint_rounding>.<simdfmt>\t%<wu>0,%<wu>1"
+  [(set_attr "type" "simd_fcvt")
+   (set_attr "mode" "<MODE>")])
+
+;; Expand the standard-named patterns to <x>vfrint instructions if
+;; raising inexact exception is allowed.
+
+(define_expand "<simd_frint_pattern><mode>2"
+  [(set (match_operand:FVEC 0 "register_operand" "=f")
+       (unspec:FVEC [(match_operand:FVEC 1 "register_operand" "f")]
+                    SIMD_FRINT))]
+   "<SIMD_FRINT> == UNSPEC_SIMD_FRINT ||
+    flag_fp_int_builtin_inexact ||
+    !flag_trapping_math")
+
+;; ftrunc is like btrunc, but it's allowed to raise inexact exception
+;; even if -fno-fp-int-builtin-inexact.
+(define_expand "ftrunc<mode>2"
+  [(set (match_operand:FVEC 0 "register_operand" "=f")
+       (unspec:FVEC [(match_operand:FVEC 1 "register_operand" "f")]
+                    UNSPEC_SIMD_FRINTRZ))]
+  "")
+
+;; <x>vftint.{/rp/rz/rm}
+(define_insn
+  "<simd_isa>_<x>vftint<simd_frint_rounding>_<simdifmt_for_f>_<simdfmt>"
+  [(set (match_operand:<VIMODE> 0 "register_operand" "=f")
+       (fix:<VIMODE>
+         (unspec:FVEC [(match_operand:FVEC 1 "register_operand" "f")]
+                      SIMD_FRINT)))]
+  ""
+  "<x>vftint<simd_frint_rounding>.<simdifmt_for_f>.<simdfmt>\t%<wu>0,%<wu>1"
+  [(set_attr "type" "simd_fcvt")
+   (set_attr "mode" "<MODE>")])
+
+;; Expand the standard-named patterns to <x>vftint instructions if
+;; raising inexact exception.
+
+(define_expand "l<simd_frint_pattern><mode><vimode>2"
+  [(set (match_operand:<VIMODE> 0 "register_operand" "=f")
+       (fix:<VIMODE>
+         (unspec:FVEC [(match_operand:FVEC 1 "register_operand" "f")]
+                      SIMD_FRINT)))]
+   "<SIMD_FRINT> == UNSPEC_SIMD_FRINT ||
+    flag_fp_int_builtin_inexact ||
+    !flag_trapping_math")
+
+;; fix_trunc is allowed to raise inexact exception even if
+;; -fno-fp-int-builtin-inexact.  Because the middle end trys to match
+;; (FIX x) and it does not know (FIX (UNSPEC_SIMD_FRINTRZ x)), we need
+;; to use define_insn_and_split instead of define_expand (expanders are
+;; not considered during matching).
+(define_insn_and_split "fix_trunc<mode><vimode>2"
+  [(set (match_operand:<VIMODE> 0 "register_operand" "=f")
+       (fix:<VIMODE> (match_operand:FVEC 1 "register_operand" "f")))]
+  ""
+  "#"
+  ""
+  [(const_int 0)]
+  {
+    emit_insn (gen_<simd_isa>_<x>vftintrz_<simdifmt_for_f>_<simdfmt> (
+      operands[0], operands[1]));
+    DONE;
+  }
+  [(set_attr "type" "simd_fcvt")
+   (set_attr "mode" "<MODE>")])
+
+; The LoongArch SX Instructions.
+(include "lsx.md")
+
+; The LoongArch ASX Instructions.
+(include "lasx.md")
diff --git a/gcc/testsuite/gcc.target/loongarch/vect-frint-no-inexact.c b/gcc/testsuite/gcc.target/loongarch/vect-frint-no-inexact.c
new file mode 100644 (file)
index 0000000..7bbaf1f
--- /dev/null
@@ -0,0 +1,48 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -mabi=lp64d -mdouble-float -fno-math-errno -fno-fp-int-builtin-inexact -mlasx" } */
+
+#include "vect-frint.c"
+
+/* ceil */
+/* { dg-final { scan-assembler "bl\t%plt\\(ceil\\)" } } */
+/* { dg-final { scan-assembler "bl\t%plt\\(ceilf\\)" } } */
+/* { dg-final { scan-assembler-not "\tvfrintrp\.s" } } */
+/* { dg-final { scan-assembler-not "\tvfrintrp\.d" } } */
+/* { dg-final { scan-assembler-not "\txvfrintrp\.s" } } */
+/* { dg-final { scan-assembler-not "\txvfrintrp\.d" } } */
+
+/* floor */
+/* { dg-final { scan-assembler "bl\t%plt\\(floor\\)" } } */
+/* { dg-final { scan-assembler "bl\t%plt\\(floorf\\)" } } */
+/* { dg-final { scan-assembler-not "\tvfrintrm\.s" } } */
+/* { dg-final { scan-assembler-not "\tvfrintrm\.d" } } */
+/* { dg-final { scan-assembler-not "\txvfrintrm\.s" } } */
+/* { dg-final { scan-assembler-not "\txvfrintrm\.d" } } */
+
+/* nearbyint + rint: Only rint is allowed */
+/* { dg-final { scan-assembler "bl\t%plt\\(nearbyint\\)" } } */
+/* { dg-final { scan-assembler "bl\t%plt\\(nearbyintf\\)" } } */
+/* { dg-final { scan-assembler-times "\tvfrint\.s" 1 } } */
+/* { dg-final { scan-assembler-times "\tvfrint\.d" 1 } } */
+/* { dg-final { scan-assembler-times "\txvfrint\.s" 1 } } */
+/* { dg-final { scan-assembler-times "\txvfrint\.d" 1 } } */
+
+/* round: we don't have a corresponding instruction */
+/* { dg-final { scan-assembler "bl\t%plt\\(round\\)" } } */
+/* { dg-final { scan-assembler "bl\t%plt\\(roundf\\)" } } */
+
+/* roundeven */
+/* { dg-final { scan-assembler "bl\t%plt\\(roundeven\\)" } } */
+/* { dg-final { scan-assembler "bl\t%plt\\(roundevenf\\)" } } */
+/* { dg-final { scan-assembler-not "\tvfrintrne\.s" } } */
+/* { dg-final { scan-assembler-not "\tvfrintrne\.d" } } */
+/* { dg-final { scan-assembler-not "\txvfrintrne\.s" } } */
+/* { dg-final { scan-assembler-not "\txvfrintrne\.d" } } */
+
+/* trunc */
+/* { dg-final { scan-assembler "bl\t%plt\\(trunc\\)" } } */
+/* { dg-final { scan-assembler "bl\t%plt\\(truncf\\)" } } */
+/* { dg-final { scan-assembler-not "\tvfrintrz\.s" } } */
+/* { dg-final { scan-assembler-not "\tvfrintrz\.d" } } */
+/* { dg-final { scan-assembler-not "\txvfrintrz\.s" } } */
+/* { dg-final { scan-assembler-not "\txvfrintrz\.d" } } */
diff --git a/gcc/testsuite/gcc.target/loongarch/vect-frint.c b/gcc/testsuite/gcc.target/loongarch/vect-frint.c
new file mode 100644 (file)
index 0000000..6bf211e
--- /dev/null
@@ -0,0 +1,85 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -mabi=lp64d -mdouble-float -fno-math-errno -ffp-int-builtin-inexact -mlasx" } */
+
+float out_x[8];
+double out_y[4];
+
+float x[8];
+double y[4];
+
+#define TEST(op, N, func) \
+void \
+test_##op##_##N##_##func () \
+{ \
+  for (int i = 0; i < N; i++) \
+    out_##op[i] = __builtin_##func (op[i]); \
+}
+
+TEST(x, 4, ceilf);
+TEST(x, 4, floorf);
+TEST(x, 4, nearbyintf);
+TEST(x, 4, rintf);
+TEST(x, 4, roundf);
+TEST(x, 4, roundevenf);
+TEST(x, 4, truncf);
+
+TEST(x, 8, ceilf);
+TEST(x, 8, floorf);
+TEST(x, 8, nearbyintf);
+TEST(x, 8, rintf);
+TEST(x, 8, roundf);
+TEST(x, 8, roundevenf);
+TEST(x, 8, truncf);
+
+TEST(y, 2, ceil);
+TEST(y, 2, floor);
+TEST(y, 2, nearbyint);
+TEST(y, 2, rint);
+TEST(y, 2, round);
+TEST(y, 2, roundeven);
+TEST(y, 2, trunc);
+
+TEST(y, 4, ceil);
+TEST(y, 4, floor);
+TEST(y, 4, nearbyint);
+TEST(y, 4, rint);
+TEST(y, 4, round);
+TEST(y, 4, roundeven);
+TEST(y, 4, trunc);
+
+/* ceil */
+/* { dg-final { scan-assembler "\tvfrintrp\.s" } } */
+/* { dg-final { scan-assembler "\tvfrintrp\.d" } } */
+/* { dg-final { scan-assembler "\txvfrintrp\.s" } } */
+/* { dg-final { scan-assembler "\txvfrintrp\.d" } } */
+
+/* floor */
+/* { dg-final { scan-assembler "\tvfrintrm\.s" } } */
+/* { dg-final { scan-assembler "\tvfrintrm\.d" } } */
+/* { dg-final { scan-assembler "\txvfrintrm\.s" } } */
+/* { dg-final { scan-assembler "\txvfrintrm\.d" } } */
+
+/* rint and nearbyint
+   nearbyint has been disallowed to raise FE_INEXACT for decades.  */
+/* { dg-final { scan-assembler-times "\tvfrint\.s" 1 } } */
+/* { dg-final { scan-assembler-times "\tvfrint\.d" 1 } } */
+/* { dg-final { scan-assembler-times "\txvfrint\.s" 1 } } */
+/* { dg-final { scan-assembler-times "\txvfrint\.d" 1 } } */
+/* { dg-final { scan-assembler "bl\t%plt\\(nearbyint\\)" } } */
+/* { dg-final { scan-assembler "bl\t%plt\\(nearbyintf\\)" } } */
+
+/* round: we don't have a corresponding instruction */
+/* { dg-final { scan-assembler "bl\t%plt\\(round\\)" } } */
+/* { dg-final { scan-assembler "bl\t%plt\\(roundf\\)" } } */
+
+/* roundeven */
+/* { dg-final { scan-assembler "\tvfrintrne\.s" } } */
+/* { dg-final { scan-assembler "\tvfrintrne\.d" } } */
+/* { dg-final { scan-assembler "\txvfrintrne\.s" } } */
+/* { dg-final { scan-assembler "\txvfrintrne\.d" } } */
+
+/* trunc */
+/* { dg-final { scan-assembler "\tvfrintrz\.s" } } */
+/* { dg-final { scan-assembler "\tvfrintrz\.d" } } */
+/* { dg-final { scan-assembler "\txvfrintrz\.s" } } */
+/* { dg-final { scan-assembler "\txvfrintrz\.d" } } */
diff --git a/gcc/testsuite/gcc.target/loongarch/vect-ftint-no-inexact.c b/gcc/testsuite/gcc.target/loongarch/vect-ftint-no-inexact.c
new file mode 100644 (file)
index 0000000..83d2680
--- /dev/null
@@ -0,0 +1,44 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -mabi=lp64d -mdouble-float -fno-math-errno -fno-fp-int-builtin-inexact -mlasx" } */
+
+#include "vect-ftint.c"
+
+/* ceil */
+/* { dg-final { scan-assembler "bl\t%plt\\(ceil\\)" } } */
+/* { dg-final { scan-assembler "bl\t%plt\\(ceilf\\)" } } */
+/* { dg-final { scan-assembler-not "\tvftintrp\.w\.s" } } */
+/* { dg-final { scan-assembler-not "\tvftintrp\.l\.d" } } */
+/* { dg-final { scan-assembler-not "\txvftintrp\.w\.s" } } */
+/* { dg-final { scan-assembler-not "\txvftintrp\.l\.d" } } */
+
+/* floor */
+/* { dg-final { scan-assembler "bl\t%plt\\(floor\\)" } } */
+/* { dg-final { scan-assembler "bl\t%plt\\(floorf\\)" } } */
+/* { dg-final { scan-assembler-not "\tvftintrm\.w\.s" } } */
+/* { dg-final { scan-assembler-not "\tvftintrm\.l\.d" } } */
+/* { dg-final { scan-assembler-not "\txvftintrm\.w\.s" } } */
+/* { dg-final { scan-assembler-not "\txvftintrm\.l\.d" } } */
+
+/* nearbyint + rint */
+/* { dg-final { scan-assembler "bl\t%plt\\(floor\\)" } } */
+/* { dg-final { scan-assembler "bl\t%plt\\(floorf\\)" } } */
+/* { dg-final { scan-assembler-times "\tvftint\.w\.s" 1 } } */
+/* { dg-final { scan-assembler-times "\tvftint\.l\.d" 1 } } */
+/* { dg-final { scan-assembler-times "\txvftint\.w\.s" 1 } } */
+/* { dg-final { scan-assembler-times "\txvftint\.l\.d" 1 } } */
+
+/* round: we don't have a corresponding instruction */
+/* { dg-final { scan-assembler "bl\t%plt\\(lround\\)" } } */
+/* { dg-final { scan-assembler "bl\t%plt\\(roundf\\)" } } */
+
+/* roundeven */
+/* { dg-final { scan-assembler "bl\t%plt\\(roundeven\\)" } } */
+/* { dg-final { scan-assembler "bl\t%plt\\(roundevenf\\)" } } */
+/* { dg-final { scan-assembler-not "\tvftintrne\.w\.s" } } */
+/* { dg-final { scan-assembler-not "\tvftintrne\.l\.d" } } */
+/* { dg-final { scan-assembler-not "\txvftintrne\.w\.s" } } */
+/* { dg-final { scan-assembler-not "\txvftintrne\.l\.d" } } */
+
+/* trunc: XFAIL due to PR 107723 */
+/* { dg-final { scan-assembler "bl\t%plt\\(trunc\\)" { xfail *-*-* } } } */
+/* { dg-final { scan-assembler "bl\t%plt\\(truncf\\)" } } */
diff --git a/gcc/testsuite/gcc.target/loongarch/vect-ftint.c b/gcc/testsuite/gcc.target/loongarch/vect-ftint.c
new file mode 100644 (file)
index 0000000..c4962ed
--- /dev/null
@@ -0,0 +1,83 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -mabi=lp64d -mdouble-float -fno-math-errno -ffp-int-builtin-inexact -mlasx" } */
+
+int out_x[8];
+long out_y[4];
+
+float x[8];
+double y[4];
+
+#define TEST(op, N, func) \
+void \
+test_##op##_##N##_##func () \
+{ \
+  for (int i = 0; i < N; i++) \
+    out_##op[i] = __builtin_##func (op[i]); \
+}
+
+TEST(x, 4, ceilf);
+TEST(x, 4, floorf);
+TEST(x, 4, nearbyintf);
+TEST(x, 4, rintf);
+TEST(x, 4, roundf);
+TEST(x, 4, roundevenf);
+TEST(x, 4, truncf);
+
+TEST(x, 8, ceilf);
+TEST(x, 8, floorf);
+TEST(x, 8, nearbyintf);
+TEST(x, 8, rintf);
+TEST(x, 8, roundf);
+TEST(x, 8, roundevenf);
+TEST(x, 8, truncf);
+
+TEST(y, 2, ceil);
+TEST(y, 2, floor);
+TEST(y, 2, nearbyint);
+TEST(y, 2, rint);
+TEST(y, 2, round);
+TEST(y, 2, roundeven);
+TEST(y, 2, trunc);
+
+TEST(y, 4, ceil);
+TEST(y, 4, floor);
+TEST(y, 4, nearbyint);
+TEST(y, 4, rint);
+TEST(y, 4, round);
+TEST(y, 4, roundeven);
+TEST(y, 4, trunc);
+
+/* ceil */
+/* { dg-final { scan-assembler "\tvftintrp\.w\.s" } } */
+/* { dg-final { scan-assembler "\tvftintrp\.l\.d" } } */
+/* { dg-final { scan-assembler "\txvftintrp\.w\.s" } } */
+/* { dg-final { scan-assembler "\txvftintrp\.l\.d" } } */
+
+/* floor */
+/* { dg-final { scan-assembler "\tvftintrm\.w\.s" } } */
+/* { dg-final { scan-assembler "\tvftintrm\.l\.d" } } */
+/* { dg-final { scan-assembler "\txvftintrm\.w\.s" } } */
+/* { dg-final { scan-assembler "\txvftintrm\.l\.d" } } */
+
+/* rint and nearbyint
+   nearbyint has been disallowed to raise FE_INEXACT for decades.  */
+/* { dg-final { scan-assembler-times "\tvftint\.w\.s" 1 } } */
+/* { dg-final { scan-assembler-times "\tvftint\.l\.d" 1 } } */
+/* { dg-final { scan-assembler-times "\txvftint\.w\.s" 1 } } */
+/* { dg-final { scan-assembler-times "\txvftint\.l\.d" 1 } } */
+/* { dg-final { scan-assembler "bl\t%plt\\(nearbyint\\)" } } */
+/* { dg-final { scan-assembler "bl\t%plt\\(nearbyintf\\)" } } */
+
+/* round: we don't have a corresponding instruction */
+/* { dg-final { scan-assembler "bl\t%plt\\(lround\\)" } } */
+/* { dg-final { scan-assembler "bl\t%plt\\(roundf\\)" } } */
+
+/* roundeven */
+/* { dg-final { scan-assembler "\tvftintrne\.w\.s" } } */
+/* { dg-final { scan-assembler "\tvftintrne\.l\.d" } } */
+/* { dg-final { scan-assembler "\txvftintrne\.w\.s" } } */
+/* { dg-final { scan-assembler "\txvftintrne\.l\.d" } } */
+
+/* trunc */
+/* { dg-final { scan-assembler-not "bl\t%plt\\(trunc\\)" } } */
+/* { dg-final { scan-assembler-not "bl\t%plt\\(truncf\\)" } } */