]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
[PATCH v10] RISC-V: Add support for the Zfa extension
authorJin Ma <jinma@linux.alibaba.com>
Fri, 25 Aug 2023 21:34:40 +0000 (15:34 -0600)
committerJeff Law <jlaw@ventanamicro.com>
Fri, 25 Aug 2023 21:41:05 +0000 (15:41 -0600)
This patch adds the 'Zfa' extension for riscv, which is based on:
https://github.com/riscv/riscv-isa-manual/commits/zfb

The binutils-gdb for 'Zfa' extension:
https://sourceware.org/pipermail/binutils/2023-April/127060.html

What needs special explanation is:
1, According to riscv-spec, "The FCVTMO D.W.D instruction was added principally to
  accelerate the processing of JavaScript Numbers.", so it seems that no implementation
  is required.

2, The instructions FMINM and FMAXM correspond to C23 library function fminimum and fmaximum.
  Therefore, this patch has simply implemented the pattern of fminm<hf\sf\df>3 and
  fmaxm<hf\sf\df>3 to prepare for later.

gcc/ChangeLog:

* common/config/riscv/riscv-common.cc: Add zfa extension version, which depends on
the F extension.
* config/riscv/constraints.md (zfli): Constrain the floating point number that the
instructions FLI.H/S/D can load.
* config/riscv/iterators.md (ceil): New.
* config/riscv/riscv-opts.h (MASK_ZFA): New.
(TARGET_ZFA): New.
* config/riscv/riscv-protos.h (riscv_float_const_rtx_index_for_fli): New.
* config/riscv/riscv.cc (riscv_float_const_rtx_index_for_fli): New.
(riscv_cannot_force_const_mem): If instruction FLI.H/S/D can be used, memory is
not applicable.
(riscv_const_insns): Likewise.
(riscv_legitimize_const_move): Likewise.
(riscv_split_64bit_move_p): If instruction FLI.H/S/D can be used, no split is
required.
(riscv_split_doubleword_move): Likewise.
(riscv_output_move): Output the mov instructions in zfa extension.
(riscv_print_operand): Output the floating-point value of the FLI.H/S/D immediate
in assembly.
(riscv_secondary_memory_needed): Likewise.
* config/riscv/riscv.md (fminm<mode>3): New.
(fmaxm<mode>3): New.
(movsidf2_low_rv32): New.
(movsidf2_high_rv32): New.
(movdfsisi3_rv32): New.
(f<quiet_pattern>_quiet<ANYF:mode><X:mode>4_zfa): New.
* config/riscv/riscv.opt: New.

gcc/testsuite/ChangeLog:

* gcc.target/riscv/zfa-fleq-fltq.c: New test.
* gcc.target/riscv/zfa-fli-zfh.c: New test.
* gcc.target/riscv/zfa-fli.c: New test.
* gcc.target/riscv/zfa-fmovh-fmovp.c: New test.
* gcc.target/riscv/zfa-fli-1.c: New test.
* gcc.target/riscv/zfa-fli-2.c: New test.
* gcc.target/riscv/zfa-fli-3.c: New test.
* gcc.target/riscv/zfa-fli-4.c: New test.
* gcc.target/riscv/zfa-fli-6.c: New test.
* gcc.target/riscv/zfa-fli-7.c: New test.
* gcc.target/riscv/zfa-fli-8.c: New test.

Co-authored-by: Tsukasa OI <research_trasio@irq.a4lg.com>
20 files changed:
gcc/common/config/riscv/riscv-common.cc
gcc/config/riscv/constraints.md
gcc/config/riscv/iterators.md
gcc/config/riscv/riscv-opts.h
gcc/config/riscv/riscv-protos.h
gcc/config/riscv/riscv.cc
gcc/config/riscv/riscv.md
gcc/config/riscv/riscv.opt
gcc/testsuite/gcc.target/riscv/zfa-fleq-fltq.c [new file with mode: 0644]
gcc/testsuite/gcc.target/riscv/zfa-fli-1.c [new file with mode: 0644]
gcc/testsuite/gcc.target/riscv/zfa-fli-2.c [new file with mode: 0644]
gcc/testsuite/gcc.target/riscv/zfa-fli-3.c [new file with mode: 0644]
gcc/testsuite/gcc.target/riscv/zfa-fli-4.c [new file with mode: 0644]
gcc/testsuite/gcc.target/riscv/zfa-fli-6.c [new file with mode: 0644]
gcc/testsuite/gcc.target/riscv/zfa-fli-7.c [new file with mode: 0644]
gcc/testsuite/gcc.target/riscv/zfa-fli-8.c [new file with mode: 0644]
gcc/testsuite/gcc.target/riscv/zfa-fli-zfh.c [new file with mode: 0644]
gcc/testsuite/gcc.target/riscv/zfa-fli.c [new file with mode: 0644]
gcc/testsuite/gcc.target/riscv/zfa-fmovh-fmovp.c [new file with mode: 0644]
gcc/testsuite/gcc.target/riscv/zfa-fround.c [new file with mode: 0644]

index 82330110740c329435a55c96e3945acf02bc340c..128a702017225c7d3bd91abcb4b91007e8cd02d5 100644 (file)
@@ -123,6 +123,9 @@ static const riscv_implied_info_t riscv_implied_info[] =
 
   {"zfh", "zfhmin"},
   {"zfhmin", "f"},
+
+  {"zfa", "f"},
+
   {"zvfhmin", "zve32f"},
   {"zvfh", "zve32f"},
   {"zvfh", "zfhmin"},
@@ -272,6 +275,8 @@ static const struct riscv_ext_version riscv_ext_version_table[] =
   {"zvfhmin",   ISA_SPEC_CLASS_NONE, 1, 0},
   {"zvfh",      ISA_SPEC_CLASS_NONE, 1, 0},
 
+  {"zfa",     ISA_SPEC_CLASS_NONE, 0, 1},
+
   {"zmmul", ISA_SPEC_CLASS_NONE, 1, 0},
 
   {"zca",  ISA_SPEC_CLASS_NONE, 1, 0},
@@ -1434,6 +1439,8 @@ static const riscv_ext_flag_table_t riscv_ext_flag_table[] =
   {"zvfhmin",   &gcc_options::x_riscv_zf_subext, MASK_ZVFHMIN},
   {"zvfh",      &gcc_options::x_riscv_zf_subext, MASK_ZVFH},
 
+  {"zfa",       &gcc_options::x_riscv_zfa_subext, MASK_ZFA},
+
   {"zmmul", &gcc_options::x_riscv_zm_subext, MASK_ZMMUL},
 
   /* Code-size reduction extensions.  */
index 44525b2da49124f4b5dfafa97785681116515344..3f52bc76f67f8e0044e16d451e9b92eaa9b19646 100644 (file)
   (and (match_operand 0 "move_operand")
        (match_test "CONSTANT_P (op)")))
 
+;; Zfa constraints.
+
+(define_constraint "zfli"
+  "A floating point number that can be loaded using instruction `fli` in zfa."
+  (and (match_code "const_double")
+       (match_test "TARGET_ZFA && (riscv_float_const_rtx_index_for_fli (op) != -1)")))
+
+(define_register_constraint "zmvf" "(TARGET_ZFA || TARGET_XTHEADFMV) ? FP_REGS : NO_REGS"
+  "A floating-point register for ZFA or XTheadFmv.")
+
+(define_register_constraint "zmvr" "(TARGET_ZFA || TARGET_XTHEADFMV) ? GR_REGS : NO_REGS"
+  "An integer register for  ZFA or XTheadFmv.")
+
 ;; Vector constraints.
 
 (define_register_constraint "vr" "TARGET_VECTOR ? V_REGS : NO_REGS"
   "Vector duplicate memory operand"
   (and (match_code "mem")
        (match_code "reg" "0")))
-
-;; Vendor ISA extension constraints.
-
-(define_register_constraint "th_f_fmv" "TARGET_XTHEADFMV ? FP_REGS : NO_REGS"
-  "A floating-point register for XTheadFmv.")
-
-(define_register_constraint "th_r_fmv" "TARGET_XTHEADFMV ? GR_REGS : NO_REGS"
-  "An integer register for XTheadFmv.")
index 500bbc39a6b04f0edd8c39177543cab32dcdf077..a4070de151080b6dc5462d6e42b1c424bfd5d77b 100644 (file)
 (define_int_attr quiet_pattern [(UNSPEC_FLT_QUIET "lt") (UNSPEC_FLE_QUIET "le")])
 (define_int_attr QUIET_PATTERN [(UNSPEC_FLT_QUIET "LT") (UNSPEC_FLE_QUIET "LE")])
 
+(define_int_iterator ROUND [UNSPEC_ROUND UNSPEC_FLOOR UNSPEC_CEIL UNSPEC_BTRUNC UNSPEC_ROUNDEVEN UNSPEC_NEARBYINT])
+(define_int_attr round_pattern [(UNSPEC_ROUND "round") (UNSPEC_FLOOR "floor") (UNSPEC_CEIL "ceil")
+                               (UNSPEC_BTRUNC "btrunc") (UNSPEC_ROUNDEVEN "roundeven") (UNSPEC_NEARBYINT "nearbyint")])
+(define_int_attr round_rm [(UNSPEC_ROUND "rmm") (UNSPEC_FLOOR "rdn") (UNSPEC_CEIL "rup")
+                          (UNSPEC_BTRUNC "rtz") (UNSPEC_ROUNDEVEN "rne") (UNSPEC_NEARBYINT "dyn")])
index 378a17699cd75d9f32a6cd1333dcbbc80345101c..b1e05967c1f874cc1eaac0d627f7c8964880f28b 100644 (file)
@@ -245,6 +245,9 @@ enum riscv_entity
 #define MASK_ZICOND   (1 << 2)
 #define TARGET_ZICOND ((riscv_zi_subext & MASK_ZICOND) != 0)
 
+#define MASK_ZFA   (1 << 0)
+#define TARGET_ZFA    ((riscv_zfa_subext & MASK_ZFA) != 0)
+
 #define MASK_ZFHMIN   (1 << 0)
 #define MASK_ZFH      (1 << 1)
 #define MASK_ZVFHMIN  (1 << 2)
index 2c4405c986067f03745e467e939267e071be257a..56db7d98f55b4d2369eeac334aa5ad70a661ba60 100644 (file)
@@ -83,6 +83,7 @@ struct riscv_address_info {
 /* Routines implemented in riscv.cc.  */
 extern enum riscv_symbol_type riscv_classify_symbolic_expression (rtx);
 extern bool riscv_symbolic_constant_p (rtx, enum riscv_symbol_type *);
+extern int riscv_float_const_rtx_index_for_fli (rtx);
 extern int riscv_regno_mode_ok_for_base_p (int, machine_mode, bool);
 extern enum reg_class riscv_index_reg_class ();
 extern int riscv_regno_ok_for_index_p (int);
index 98a46b00ceb53f3d9a236b9abd293e89aa14f531..1d6e278ea90ace139559d01653ff69f655269a9a 100644 (file)
@@ -805,6 +805,138 @@ static int riscv_symbol_insns (enum riscv_symbol_type type)
     }
 }
 
+/* Immediate values loaded by the FLI.S instruction in Chapter 25 of the latest RISC-V ISA
+   Manual draft. For details, please see:
+   https://github.com/riscv/riscv-isa-manual/releases/tag/isa-449cd0c  */
+
+static unsigned HOST_WIDE_INT fli_value_hf[32] =
+{
+  0xbcp8, 0x4p8, 0x1p8, 0x2p8, 0x1cp8, 0x20p8, 0x2cp8, 0x30p8,
+  0x34p8, 0x35p8, 0x36p8, 0x37p8, 0x38p8, 0x39p8, 0x3ap8, 0x3bp8,
+  0x3cp8, 0x3dp8, 0x3ep8, 0x3fp8, 0x40p8, 0x41p8, 0x42p8, 0x44p8,
+  0x48p8, 0x4cp8, 0x58p8, 0x5cp8, 0x78p8,
+  /* Only used for filling, ensuring that 29 and 30 of HF are the same.  */
+  0x78p8,
+  0x7cp8, 0x7ep8
+};
+
+static unsigned HOST_WIDE_INT fli_value_sf[32] =
+{
+  0xbf8p20, 0x008p20, 0x378p20, 0x380p20, 0x3b8p20, 0x3c0p20, 0x3d8p20, 0x3e0p20,
+  0x3e8p20, 0x3eap20, 0x3ecp20, 0x3eep20, 0x3f0p20, 0x3f2p20, 0x3f4p20, 0x3f6p20,
+  0x3f8p20, 0x3fap20, 0x3fcp20, 0x3fep20, 0x400p20, 0x402p20, 0x404p20, 0x408p20,
+  0x410p20, 0x418p20, 0x430p20, 0x438p20, 0x470p20, 0x478p20, 0x7f8p20, 0x7fcp20
+};
+
+static unsigned HOST_WIDE_INT fli_value_df[32] =
+{
+  0xbff0p48, 0x10p48, 0x3ef0p48, 0x3f00p48,
+  0x3f70p48, 0x3f80p48, 0x3fb0p48, 0x3fc0p48,
+  0x3fd0p48, 0x3fd4p48, 0x3fd8p48, 0x3fdcp48,
+  0x3fe0p48, 0x3fe4p48, 0x3fe8p48, 0x3fecp48,
+  0x3ff0p48, 0x3ff4p48, 0x3ff8p48, 0x3ffcp48,
+  0x4000p48, 0x4004p48, 0x4008p48, 0x4010p48,
+  0x4020p48, 0x4030p48, 0x4060p48, 0x4070p48,
+  0x40e0p48, 0x40f0p48, 0x7ff0p48, 0x7ff8p48
+};
+
+/* Display floating-point values at the assembly level, which is consistent
+   with the zfa extension of llvm:
+   https://reviews.llvm.org/D145645.  */
+
+const char *fli_value_print[32] =
+{
+  "-1.0", "min", "1.52587890625e-05", "3.0517578125e-05", "0.00390625", "0.0078125", "0.0625", "0.125",
+  "0.25", "0.3125", "0.375", "0.4375", "0.5", "0.625", "0.75", "0.875",
+  "1.0", "1.25", "1.5", "1.75", "2.0", "2.5", "3.0", "4.0",
+  "8.0", "16.0", "128.0", "256.0", "32768.0", "65536.0", "inf", "nan"
+};
+
+/* Return index of the FLI instruction table if rtx X is an immediate constant that can
+   be moved using a single FLI instruction in zfa extension. Return -1 if not found.  */
+
+int
+riscv_float_const_rtx_index_for_fli (rtx x)
+{
+  unsigned HOST_WIDE_INT *fli_value_array;
+
+  machine_mode mode = GET_MODE (x);
+
+  if (!TARGET_ZFA
+      || !CONST_DOUBLE_P(x)
+      || mode == VOIDmode
+      || (mode == HFmode && !TARGET_ZFH)
+      || (mode == SFmode && !TARGET_HARD_FLOAT)
+      || (mode == DFmode && !TARGET_DOUBLE_FLOAT))
+    return -1;
+
+  if (!SCALAR_FLOAT_MODE_P (mode)
+      || GET_MODE_BITSIZE (mode).to_constant () > HOST_BITS_PER_WIDE_INT
+      /* Only support up to DF mode.  */
+      || GET_MODE_BITSIZE (mode).to_constant () > GET_MODE_BITSIZE (DFmode))
+    return -1;
+
+  unsigned HOST_WIDE_INT ival = 0;
+
+  long res[2];
+  real_to_target (res,
+                 CONST_DOUBLE_REAL_VALUE (x),
+                 REAL_MODE_FORMAT (mode));
+
+  if (mode == DFmode)
+    {
+      int order = BYTES_BIG_ENDIAN ? 1 : 0;
+      ival = zext_hwi (res[order], 32);
+      ival |= (zext_hwi (res[1 - order], 32) << 32);
+
+      /* When the lower 32 bits are not all 0, it is impossible to be in the table.  */
+      if (ival & (unsigned HOST_WIDE_INT)0xffffffff)
+       return -1;
+    }
+  else
+      ival = zext_hwi (res[0], 32);
+
+  switch (mode)
+    {
+      case E_HFmode:
+       fli_value_array = fli_value_hf;
+       break;
+      case E_SFmode:
+       fli_value_array = fli_value_sf;
+       break;
+      case E_DFmode:
+       fli_value_array = fli_value_df;
+       break;
+      default:
+       return -1;
+    }
+
+  if (fli_value_array[0] == ival)
+    return 0;
+
+  if (fli_value_array[1] == ival)
+    return 1;
+
+  /* Perform a binary search to find target index.  */
+  unsigned l, r, m;
+
+  l = 2;
+  r = 31;
+
+  while (l <= r)
+    {
+      m = (l + r) / 2;
+      if (fli_value_array[m] == ival)
+       return m;
+      else if (fli_value_array[m] < ival)
+       l = m+1;
+      else
+       r = m-1;
+    }
+
+  return -1;
+}
+
 /* Implement TARGET_LEGITIMATE_CONSTANT_P.  */
 
 static bool
@@ -832,6 +964,9 @@ riscv_cannot_force_const_mem (machine_mode mode ATTRIBUTE_UNUSED, rtx x)
   if (GET_CODE (x) == HIGH)
     return true;
 
+  if (satisfies_constraint_zfli (x))
+   return true;
+
   split_const (x, &base, &offset);
   if (riscv_symbolic_constant_p (base, &type))
     {
@@ -1324,6 +1459,10 @@ riscv_const_insns (rtx x)
       }
 
     case CONST_DOUBLE:
+      /* See if we can use FMV directly.  */
+      if (satisfies_constraint_zfli (x))
+       return 1;
+
       /* We can use x0 to load floating-point zero.  */
       return x == CONST0_RTX (GET_MODE (x)) ? 1 : 0;
     case CONST_VECTOR:
@@ -1946,6 +2085,12 @@ riscv_legitimize_const_move (machine_mode mode, rtx dest, rtx src)
       return;
     }
 
+  if (satisfies_constraint_zfli (src))
+    {
+      riscv_emit_set (dest, src);
+      return;
+    }
+
   /* Split moves of symbolic constants into high/low pairs.  */
   if (riscv_split_symbol (dest, src, MAX_MACHINE_MODE, &src))
     {
@@ -2995,6 +3140,10 @@ riscv_split_64bit_move_p (rtx dest, rtx src)
   if (TARGET_64BIT)
     return false;
 
+  /* There is no need to split if the FLI instruction in the `Zfa` extension can be used.  */
+  if (satisfies_constraint_zfli (src))
+    return false;
+
   /* Allow FPR <-> FPR and FPR <-> MEM moves, and permit the special case
      of zeroing an FPR with FCVT.D.W.  */
   if (TARGET_DOUBLE_FLOAT
@@ -3014,22 +3163,36 @@ riscv_split_64bit_move_p (rtx dest, rtx src)
 void
 riscv_split_doubleword_move (rtx dest, rtx src)
 {
-  /* XTheadFmv has instructions for accessing the upper bits of a double.  */
-  if (!TARGET_64BIT && TARGET_XTHEADFMV)
+  /* ZFA or XTheadFmv has instructions for accessing the upper bits of a double.  */
+  if (!TARGET_64BIT && (TARGET_ZFA || TARGET_XTHEADFMV))
     {
       if (FP_REG_RTX_P (dest))
        {
          rtx low_src = riscv_subword (src, false);
          rtx high_src = riscv_subword (src, true);
-         emit_insn (gen_th_fmv_hw_w_x (dest, high_src, low_src));
+
+         if (TARGET_ZFA)
+           emit_insn (gen_movdfsisi3_rv32 (dest, high_src, low_src));
+         else
+           emit_insn (gen_th_fmv_hw_w_x (dest, high_src, low_src));
          return;
        }
       if (FP_REG_RTX_P (src))
        {
          rtx low_dest = riscv_subword (dest, false);
          rtx high_dest = riscv_subword (dest, true);
-         emit_insn (gen_th_fmv_x_w (low_dest, src));
-         emit_insn (gen_th_fmv_x_hw (high_dest, src));
+
+         if (TARGET_ZFA)
+           {
+             emit_insn (gen_movsidf2_low_rv32 (low_dest, src));
+             emit_insn (gen_movsidf2_high_rv32 (high_dest, src));
+             return;
+           }
+         else
+           {
+             emit_insn (gen_th_fmv_x_w (low_dest, src));
+             emit_insn (gen_th_fmv_x_hw (high_dest, src));
+           }
          return;
        }
     }
@@ -3193,6 +3356,17 @@ riscv_output_move (rtx dest, rtx src)
          case 8:
            return "fld\t%0,%1";
          }
+
+      if (src_code == CONST_DOUBLE && satisfies_constraint_zfli (src))
+       switch (width)
+         {
+           case 2:
+             return "fli.h\t%0,%1";
+           case 4:
+             return "fli.s\t%0,%1";
+           case 8:
+             return "fli.d\t%0,%1";
+         }
     }
   if (dest_code == REG && GP_REG_P (REGNO (dest)) && src_code == CONST_POLY_INT)
     {
@@ -5122,6 +5296,24 @@ riscv_print_operand (FILE *file, rtx op, int letter)
            output_address (mode, XEXP (op, 0));
          break;
 
+       case CONST_DOUBLE:
+         {
+           if (letter == 'z' && op == CONST0_RTX (GET_MODE (op)))
+             {
+               fputs (reg_names[GP_REG_FIRST], file);
+               break;
+             }
+
+           int fli_index = riscv_float_const_rtx_index_for_fli (op);
+           if (fli_index == -1 || fli_index > 31)
+             {
+               output_operand_lossage ("invalid use of '%%%c'", letter);
+               break;
+             }
+           asm_fprintf (file, "%s", fli_value_print[fli_index]);
+           break;
+         }
+
        default:
          if (letter == 'z' && op == CONST0_RTX (GET_MODE (op)))
            fputs (reg_names[GP_REG_FIRST], file);
@@ -6530,7 +6722,8 @@ riscv_secondary_memory_needed (machine_mode mode, reg_class_t class1,
   return (!riscv_v_ext_mode_p (mode)
          && GET_MODE_SIZE (mode).to_constant () > UNITS_PER_WORD
          && (class1 == FP_REGS) != (class2 == FP_REGS)
-         && !TARGET_XTHEADFMV);
+         && !TARGET_XTHEADFMV
+         && !TARGET_ZFA);
 }
 
 /* Implement TARGET_REGISTER_MOVE_COST.  */
index b456fa6abb3c5f284068f8b9d1a646d4cf6afb92..47d14d999030620657968b78f04b924d33453f9a 100644 (file)
   UNSPEC_FLT_QUIET
   UNSPEC_FLE_QUIET
   UNSPEC_COPYSIGN
+  UNSPEC_RINT
+  UNSPEC_ROUND
+  UNSPEC_FLOOR
+  UNSPEC_CEIL
+  UNSPEC_BTRUNC
+  UNSPEC_ROUNDEVEN
+  UNSPEC_NEARBYINT
   UNSPEC_LRINT
   UNSPEC_LROUND
   UNSPEC_FMIN
   UNSPEC_FMAX
+  UNSPEC_FMINM
+  UNSPEC_FMAXM
 
   ;; Stack tie
   UNSPEC_TIE
 ;;
 ;;  ....................
 
+(define_insn "fminm<mode>3"
+  [(set (match_operand:ANYF                    0 "register_operand" "=f")
+       (unspec:ANYF [(use (match_operand:ANYF 1 "register_operand" " f"))
+                     (use (match_operand:ANYF 2 "register_operand" " f"))]
+                    UNSPEC_FMINM))]
+  "TARGET_HARD_FLOAT && TARGET_ZFA"
+  "fminm.<fmt>\t%0,%1,%2"
+  [(set_attr "type" "fmove")
+   (set_attr "mode" "<UNITMODE>")])
+
+(define_insn "fmaxm<mode>3"
+  [(set (match_operand:ANYF                    0 "register_operand" "=f")
+       (unspec:ANYF [(use (match_operand:ANYF 1 "register_operand" " f"))
+                     (use (match_operand:ANYF 2 "register_operand" " f"))]
+                    UNSPEC_FMAXM))]
+  "TARGET_HARD_FLOAT && TARGET_ZFA"
+  "fmaxm.<fmt>\t%0,%1,%2"
+  [(set_attr "type" "fmove")
+   (set_attr "mode" "<UNITMODE>")])
+
 (define_insn "fmin<mode>3"
   [(set (match_operand:ANYF                    0 "register_operand" "=f")
        (unspec:ANYF [(use (match_operand:ANYF 1 "register_operand" " f"))
 })
 
 (define_insn "*movhf_hardfloat"
-  [(set (match_operand:HF 0 "nonimmediate_operand" "=f,f,f,m,m,*f,*r,  *r,*r,*m")
-       (match_operand:HF 1 "move_operand"         " f,G,m,f,G,*r,*f,*G*r,*m,*r"))]
+  [(set (match_operand:HF 0 "nonimmediate_operand" "=f,   f,f,f,m,m,*f,*r,  *r,*r,*m")
+       (match_operand:HF 1 "move_operand"         " f,zfli,G,m,f,G,*r,*f,*G*r,*m,*r"))]
   "TARGET_ZFHMIN
    && (register_operand (operands[0], HFmode)
        || reg_or_0_operand (operands[1], HFmode))"
   { return riscv_output_move (operands[0], operands[1]); }
-  [(set_attr "move_type" "fmove,mtc,fpload,fpstore,store,mtc,mfc,move,load,store")
+  [(set_attr "move_type" "fmove,fmove,mtc,fpload,fpstore,store,mtc,mfc,move,load,store")
    (set_attr "mode" "HF")])
 
 (define_insn "*movhf_softfloat"
   [(set_attr "type" "fcvt")
    (set_attr "mode" "<ANYF:MODE>")])
 
+(define_insn "<round_pattern><ANYF:mode>2"
+  [(set (match_operand:ANYF     0 "register_operand" "=f")
+       (unspec:ANYF
+           [(match_operand:ANYF 1 "register_operand" " f")]
+       ROUND))]
+  "TARGET_HARD_FLOAT && TARGET_ZFA"
+  "fround.<ANYF:fmt>\t%0,%1,<round_rm>"
+  [(set_attr "type" "fcvt")
+   (set_attr "mode" "<ANYF:MODE>")])
+
+(define_insn "rint<ANYF:mode>2"
+  [(set (match_operand:ANYF     0 "register_operand" "=f")
+       (unspec:ANYF
+           [(match_operand:ANYF 1 "register_operand" " f")]
+       UNSPEC_RINT))]
+  "TARGET_HARD_FLOAT && TARGET_ZFA"
+  "froundnx.<ANYF:fmt>\t%0,%1"
+  [(set_attr "type" "fcvt")
+   (set_attr "mode" "<ANYF:MODE>")])
+
 ;;
 ;;  ....................
 ;;
 })
 
 (define_insn "*movsf_hardfloat"
-  [(set (match_operand:SF 0 "nonimmediate_operand" "=f,f,f,m,m,*f,*r,  *r,*r,*m")
-       (match_operand:SF 1 "move_operand"         " f,G,m,f,G,*r,*f,*G*r,*m,*r"))]
+  [(set (match_operand:SF 0 "nonimmediate_operand" "=f,   f,f,f,m,m,*f,*r,  *r,*r,*m")
+       (match_operand:SF 1 "move_operand"         " f,zfli,G,m,f,G,*r,*f,*G*r,*m,*r"))]
   "TARGET_HARD_FLOAT
    && (register_operand (operands[0], SFmode)
        || reg_or_0_operand (operands[1], SFmode))"
   { return riscv_output_move (operands[0], operands[1]); }
-  [(set_attr "move_type" "fmove,mtc,fpload,fpstore,store,mtc,mfc,move,load,store")
+  [(set_attr "move_type" "fmove,fmove,mtc,fpload,fpstore,store,mtc,mfc,move,load,store")
    (set_attr "mode" "SF")])
 
 (define_insn "*movsf_softfloat"
 ;; In RV32, we lack fmv.x.d and fmv.d.x.  Go through memory instead.
 ;; (However, we can still use fcvt.d.w to zero a floating-point register.)
 (define_insn "*movdf_hardfloat_rv32"
-  [(set (match_operand:DF 0 "nonimmediate_operand" "=f,f,f,m,m,*th_f_fmv,*th_r_fmv,  *r,*r,*m")
-       (match_operand:DF 1 "move_operand"         " f,G,m,f,G,*th_r_fmv,*th_f_fmv,*r*G,*m,*r"))]
+  [(set (match_operand:DF 0 "nonimmediate_operand" "=f,   f,f,f,m,m,*zmvf,*zmvr,  *r,*r,*m")
+       (match_operand:DF 1 "move_operand"         " f,zfli,G,m,f,G,*zmvr,*zmvf,*r*G,*m,*r"))]
   "!TARGET_64BIT && TARGET_DOUBLE_FLOAT
    && (register_operand (operands[0], DFmode)
        || reg_or_0_operand (operands[1], DFmode))"
   { return riscv_output_move (operands[0], operands[1]); }
-  [(set_attr "move_type" "fmove,mtc,fpload,fpstore,store,mtc,mfc,move,load,store")
+  [(set_attr "move_type" "fmove,fmove,mtc,fpload,fpstore,store,mtc,mfc,move,load,store")
    (set_attr "mode" "DF")])
 
 (define_insn "*movdf_hardfloat_rv64"
-  [(set (match_operand:DF 0 "nonimmediate_operand" "=f,f,f,m,m,*f,*r,  *r,*r,*m")
-       (match_operand:DF 1 "move_operand"         " f,G,m,f,G,*r,*f,*r*G,*m,*r"))]
+  [(set (match_operand:DF 0 "nonimmediate_operand" "=f,   f,f,f,m,m,*f,*r,  *r,*r,*m")
+       (match_operand:DF 1 "move_operand"         " f,zfli,G,m,f,G,*r,*f,*r*G,*m,*r"))]
   "TARGET_64BIT && TARGET_DOUBLE_FLOAT
    && (register_operand (operands[0], DFmode)
        || reg_or_0_operand (operands[1], DFmode))"
   { return riscv_output_move (operands[0], operands[1]); }
-  [(set_attr "move_type" "fmove,mtc,fpload,fpstore,store,mtc,mfc,move,load,store")
+  [(set_attr "move_type" "fmove,fmove,mtc,fpload,fpstore,store,mtc,mfc,move,load,store")
    (set_attr "mode" "DF")])
 
 (define_insn "*movdf_softfloat"
   [(set_attr "move_type" "move,load,store")
    (set_attr "mode" "DF")])
 
+(define_insn "movsidf2_low_rv32"
+  [(set (match_operand:SI      0 "register_operand" "=  r")
+       (truncate:SI
+           (match_operand:DF 1 "register_operand"  "zmvf")))]
+  "TARGET_HARD_FLOAT && !TARGET_64BIT && TARGET_ZFA"
+  "fmv.x.w\t%0,%1"
+  [(set_attr "move_type" "fmove")
+   (set_attr "mode" "DF")])
+
+
+(define_insn "movsidf2_high_rv32"
+  [(set (match_operand:SI      0 "register_operand"    "=  r")
+       (truncate:SI
+            (lshiftrt:DF
+                (match_operand:DF 1 "register_operand" "zmvf")
+                (const_int 32))))]
+  "TARGET_HARD_FLOAT && !TARGET_64BIT && TARGET_ZFA"
+  "fmvh.x.d\t%0,%1"
+  [(set_attr "move_type" "fmove")
+   (set_attr "mode" "DF")])
+
+(define_insn "movdfsisi3_rv32"
+  [(set (match_operand:DF      0 "register_operand"    "=  f")
+       (plus:DF
+            (match_operand:SI 2 "register_operand"     "zmvr")
+            (ashift:SI
+                (match_operand:SI 1 "register_operand" "zmvr")
+                (const_int 32))))]
+  "TARGET_HARD_FLOAT && !TARGET_64BIT && TARGET_ZFA"
+  "fmvp.d.x\t%0,%2,%1"
+  [(set_attr "move_type" "fmove")
+   (set_attr "mode" "DF")])
+
 (define_split
   [(set (match_operand:MOVE64 0 "nonimmediate_operand")
        (match_operand:MOVE64 1 "move_operand"))]
   rtx op0 = operands[0];
   rtx op1 = operands[1];
   rtx op2 = operands[2];
-  rtx tmp = gen_reg_rtx (SImode);
-  rtx cmp = gen_rtx_<QUIET_PATTERN> (<X:MODE>mode, op1, op2);
-  rtx frflags = gen_rtx_UNSPEC_VOLATILE (SImode, gen_rtvec (1, const0_rtx),
-                                        UNSPECV_FRFLAGS);
-  rtx fsflags = gen_rtx_UNSPEC_VOLATILE (SImode, gen_rtvec (1, tmp),
-                                        UNSPECV_FSFLAGS);
-
-  emit_insn (gen_rtx_SET (tmp, frflags));
-  emit_insn (gen_rtx_SET (op0, cmp));
-  emit_insn (fsflags);
+
+  if (TARGET_ZFA)
+    emit_insn (gen_f<quiet_pattern>_quiet<ANYF:mode><X:mode>4_zfa(op0, op1, op2));
+  else
+    {
+      rtx tmp = gen_reg_rtx (SImode);
+      rtx cmp = gen_rtx_<QUIET_PATTERN> (<X:MODE>mode, op1, op2);
+      rtx frflags = gen_rtx_UNSPEC_VOLATILE (SImode, gen_rtvec (1, const0_rtx),
+                                            UNSPECV_FRFLAGS);
+      rtx fsflags = gen_rtx_UNSPEC_VOLATILE (SImode, gen_rtvec (1, tmp),
+                                            UNSPECV_FSFLAGS);
+
+      emit_insn (gen_rtx_SET (tmp, frflags));
+      emit_insn (gen_rtx_SET (op0, cmp));
+      emit_insn (fsflags);
+    }
+
   if (HONOR_SNANS (<ANYF:MODE>mode))
     emit_insn (gen_rtx_UNSPEC_VOLATILE (<ANYF:MODE>mode,
                                        gen_rtvec (2, op1, op2),
   DONE;
 })
 
+(define_insn "f<quiet_pattern>_quiet<ANYF:mode><X:mode>4_zfa"
+   [(set (match_operand:X      0 "register_operand" "=r")
+        (unspec:X
+         [(match_operand:ANYF 1 "register_operand" " f")
+          (match_operand:ANYF 2 "register_operand" " f")]
+         QUIET_COMPARISON))]
+  "TARGET_HARD_FLOAT && TARGET_ZFA"
+  "f<quiet_pattern>q.<fmt>\t%0,%1,%2"
+  [(set_attr "type" "fcmp")
+   (set_attr "mode" "<UNITMODE>")
+   (set (attr "length") (const_int 16))])
+
 (define_insn "*seq_zero_<X:mode><GPR:mode>"
   [(set (match_operand:GPR       0 "register_operand" "=r")
        (eq:GPR (match_operand:X 1 "register_operand" " r")
index a962ea8f9d4153b1198b2a6ff99f2095322492a4..d2407c3c502137e17ec552961515ed1647d6521d 100644 (file)
@@ -239,6 +239,9 @@ int riscv_zicmo_subext
 TargetVariable
 int riscv_zf_subext
 
+TargetVariable
+int riscv_zfa_subext
+
 TargetVariable
 int riscv_zm_subext
 
diff --git a/gcc/testsuite/gcc.target/riscv/zfa-fleq-fltq.c b/gcc/testsuite/gcc.target/riscv/zfa-fleq-fltq.c
new file mode 100644 (file)
index 0000000..7c28b0b
--- /dev/null
@@ -0,0 +1,20 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv32imafdc_zfa -mabi=ilp32d" { target { rv32 } } } */
+/* { dg-options "-march=rv64imafdc_zfa -mabi=lp64d" { target { rv64 } } } */
+
+extern void abort(void);
+extern float a, b;
+extern double c, d;
+
+void 
+foo()
+{
+  if ((__builtin_isless(a, b) ||  __builtin_islessequal(c, d))
+      && (__builtin_islessequal(a, b)|| __builtin_isless(c, d)))
+    abort();
+}
+
+/* { dg-final { scan-assembler-times "fleq.s" 1 } } */
+/* { dg-final { scan-assembler-times "fltq.s" 1 } } */
+/* { dg-final { scan-assembler-times "fleq.d" 1 } } */
+/* { dg-final { scan-assembler-times "fltq.d" 1 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/zfa-fli-1.c b/gcc/testsuite/gcc.target/riscv/zfa-fli-1.c
new file mode 100644 (file)
index 0000000..35ea5c4
--- /dev/null
@@ -0,0 +1,24 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64imfd_zfa -mabi=lp64d"  { target { rv64 } } } */
+/* { dg-options "-march=rv32imfd_zfa -mabi=ilp32d" { target { rv32 } } } */
+/* { dg-skip-if "" { *-*-* } {"-O0" "-O1" "-Os" "-Og" "-Oz"} } */
+
+#ifndef __riscv_zfa
+#error Feature macro not defined
+#endif
+
+double
+foo_positive_d (double a)
+{
+  /* Use 3 FLI FP constants.  */
+  return (2.5 * a - 1.0) / 0.875;
+}
+
+float
+foo_positive_s (float a)
+{
+  return ((float) 2.5 * a - (float) 1.0) / (float) 0.875;
+}
+
+/* { dg-final { scan-assembler-times "fli\\.s\t" 3 } } */
+/* { dg-final { scan-assembler-times "fli\\.d\t" 3 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/zfa-fli-2.c b/gcc/testsuite/gcc.target/riscv/zfa-fli-2.c
new file mode 100644 (file)
index 0000000..10d49d1
--- /dev/null
@@ -0,0 +1,24 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64imfd_zfa -mabi=lp64d"  { target { rv64 } } } */
+/* { dg-options "-march=rv32imfd_zfa -mabi=ilp32d" { target { rv32 } } } */
+/* { dg-skip-if "" { *-*-* } {"-O0" "-O1" "-O2" "-Os" "-Og" "-Oz"} } */
+
+#ifndef __riscv_zfa
+#error Feature macro not defined
+#endif
+
+double
+foo_negative_d (double a)
+{
+  /* Use 3 "non-FLI" FP constants.  */
+  return (3.5 * a - 5.0) / 0.1875;
+}
+
+float
+foo_negative_s (float a)
+{
+  return ((float) 3.5 * a - (float) 5.0) / (float) 0.1875;
+}
+
+/* { dg-final { scan-assembler-not "fli\\.s\t" } } */
+/* { dg-final { scan-assembler-not "fli\\.d\t" } } */
diff --git a/gcc/testsuite/gcc.target/riscv/zfa-fli-3.c b/gcc/testsuite/gcc.target/riscv/zfa-fli-3.c
new file mode 100644 (file)
index 0000000..6d069b2
--- /dev/null
@@ -0,0 +1,14 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64imfd_zfa -mabi=lp64d"  { target { rv64 } } } */
+/* { dg-options "-march=rv32imfd_zfa -mabi=ilp32d" { target { rv32 } } } */
+/* { dg-skip-if "" { *-*-* } {"-O0" "-O1" "-Os" "-Og" "-Oz"} } */
+
+double
+foo_positive_s (float a)
+{
+  /* Use 3 FLI FP constants (but type conversion occur in the middle).  */
+  return (2.5f * a - 1.0) / 0.875;
+}
+
+/* { dg-final { scan-assembler-times "fli\\.s\t" 1 } } */
+/* { dg-final { scan-assembler-times "fli\\.d\t" 2 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/zfa-fli-4.c b/gcc/testsuite/gcc.target/riscv/zfa-fli-4.c
new file mode 100644 (file)
index 0000000..e72cdd6
--- /dev/null
@@ -0,0 +1,72 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64imfd_zfa_zfh -mabi=lp64d"  { target { rv64 } } } */
+/* { dg-options "-march=rv32imfd_zfa_zfh -mabi=ilp32d" { target { rv32 } } } */
+/* { dg-skip-if "" { *-*-* } {"-O0" "-Og" "-Oz"} } */
+
+#define TYPE_h _Float16
+#define TYPE_s float
+#define TYPE_d double
+
+#define DECL_TYPE(TYPE_SHORT) TYPE_##TYPE_SHORT
+
+#define DECL_FUNC(TYPE_SHORT, N, VALUE)       \
+  DECL_TYPE (TYPE_SHORT) const_##TYPE_SHORT##_##N (void)       \
+    {       \
+      return VALUE;       \
+    }
+
+#define DECL_FINITE_FUNCS(TYPE_SHORT)       \
+  DECL_FUNC (TYPE_SHORT, 00, -1)       \
+  DECL_FUNC (TYPE_SHORT, 02, 0.0000152587890625)       \
+  DECL_FUNC (TYPE_SHORT, 03, 0.000030517578125)       \
+  DECL_FUNC (TYPE_SHORT, 04, 0.00390625)       \
+  DECL_FUNC (TYPE_SHORT, 05, 0.0078125)       \
+  DECL_FUNC (TYPE_SHORT, 06, 0.0625)       \
+  DECL_FUNC (TYPE_SHORT, 07, 0.125)       \
+  DECL_FUNC (TYPE_SHORT, 08, 0.25)       \
+  DECL_FUNC (TYPE_SHORT, 09, 0.3125)       \
+  DECL_FUNC (TYPE_SHORT, 10, 0.375)       \
+  DECL_FUNC (TYPE_SHORT, 11, 0.4375)       \
+  DECL_FUNC (TYPE_SHORT, 12, 0.5)       \
+  DECL_FUNC (TYPE_SHORT, 13, 0.625)       \
+  DECL_FUNC (TYPE_SHORT, 14, 0.75)       \
+  DECL_FUNC (TYPE_SHORT, 15, 0.875)       \
+  DECL_FUNC (TYPE_SHORT, 16, 1)       \
+  DECL_FUNC (TYPE_SHORT, 17, 1.25)       \
+  DECL_FUNC (TYPE_SHORT, 18, 1.5)       \
+  DECL_FUNC (TYPE_SHORT, 19, 1.75)       \
+  DECL_FUNC (TYPE_SHORT, 20, 2)       \
+  DECL_FUNC (TYPE_SHORT, 21, 2.5)       \
+  DECL_FUNC (TYPE_SHORT, 22, 3)       \
+  DECL_FUNC (TYPE_SHORT, 23, 4)       \
+  DECL_FUNC (TYPE_SHORT, 24, 8)       \
+  DECL_FUNC (TYPE_SHORT, 25, 16)       \
+  DECL_FUNC (TYPE_SHORT, 26, 128)       \
+  DECL_FUNC (TYPE_SHORT, 27, 256)       \
+  DECL_FUNC (TYPE_SHORT, 28, 32768)       \
+  DECL_FUNC (TYPE_SHORT, 29, 65536)
+
+/* Finite numbers (except 2^16 in _Float16, making an inf).  */
+DECL_FINITE_FUNCS (h)
+DECL_FINITE_FUNCS (s)
+DECL_FINITE_FUNCS (d)
+
+/* min.  */
+DECL_FUNC (h, 01, __FLT16_MIN__)
+DECL_FUNC (s, 01, __FLT_MIN__)
+DECL_FUNC (d, 01, __DBL_MIN__)
+
+/* inf.  */
+DECL_FUNC (h, 30, __builtin_inff16 ())
+DECL_FUNC (s, 30, __builtin_inff ())
+DECL_FUNC (d, 30, __builtin_inf ())
+
+/* nan.  */
+DECL_FUNC (h, 31, __builtin_nanf16 (""))
+DECL_FUNC (s, 31, __builtin_nanf (""))
+DECL_FUNC (d, 31, __builtin_nan (""))
+
+
+/* { dg-final { scan-assembler-times "fli\\.h" 32 } } */
+/* { dg-final { scan-assembler-times "fli\\.s"  32 } } */
+/* { dg-final { scan-assembler-times "fli\\.d"  32 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/zfa-fli-6.c b/gcc/testsuite/gcc.target/riscv/zfa-fli-6.c
new file mode 100644 (file)
index 0000000..7efcd81
--- /dev/null
@@ -0,0 +1,61 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64imf_zfa_zfhmin -mabi=lp64f"  { target { rv64 } } } */
+/* { dg-options "-march=rv32imf_zfa_zfhmin -mabi=ilp32f" { target { rv32 } } } */
+/* { dg-skip-if "" { *-*-* } {"-O0" "-Og" "-Oz"} } */
+
+/* "fli.h" is unavailable even if both 'Zfa' and 'Zfhmin' is enabled.  */
+
+#define TYPE_h _Float16
+
+#define DECL_TYPE(TYPE_SHORT) TYPE_##TYPE_SHORT
+
+#define DECL_FUNC(TYPE_SHORT, N, VALUE)       \
+  DECL_TYPE (TYPE_SHORT) const_##TYPE_SHORT##_##N (void)       \
+    {       \
+      return VALUE;       \
+    }
+
+#define DECL_FINITE_FUNCS(TYPE_SHORT)       \
+  DECL_FUNC (TYPE_SHORT, 00, -1)       \
+  DECL_FUNC (TYPE_SHORT, 02, 0.0000152587890625)       \
+  DECL_FUNC (TYPE_SHORT, 03, 0.000030517578125)       \
+  DECL_FUNC (TYPE_SHORT, 04, 0.00390625)       \
+  DECL_FUNC (TYPE_SHORT, 05, 0.0078125)       \
+  DECL_FUNC (TYPE_SHORT, 06, 0.0625)       \
+  DECL_FUNC (TYPE_SHORT, 07, 0.125)       \
+  DECL_FUNC (TYPE_SHORT, 08, 0.25)       \
+  DECL_FUNC (TYPE_SHORT, 09, 0.3125)       \
+  DECL_FUNC (TYPE_SHORT, 10, 0.375)       \
+  DECL_FUNC (TYPE_SHORT, 11, 0.4375)       \
+  DECL_FUNC (TYPE_SHORT, 12, 0.5)       \
+  DECL_FUNC (TYPE_SHORT, 13, 0.625)       \
+  DECL_FUNC (TYPE_SHORT, 14, 0.75)       \
+  DECL_FUNC (TYPE_SHORT, 15, 0.875)       \
+  DECL_FUNC (TYPE_SHORT, 16, 1)       \
+  DECL_FUNC (TYPE_SHORT, 17, 1.25)       \
+  DECL_FUNC (TYPE_SHORT, 18, 1.5)       \
+  DECL_FUNC (TYPE_SHORT, 19, 1.75)       \
+  DECL_FUNC (TYPE_SHORT, 20, 2)       \
+  DECL_FUNC (TYPE_SHORT, 21, 2.5)       \
+  DECL_FUNC (TYPE_SHORT, 22, 3)       \
+  DECL_FUNC (TYPE_SHORT, 23, 4)       \
+  DECL_FUNC (TYPE_SHORT, 24, 8)       \
+  DECL_FUNC (TYPE_SHORT, 25, 16)       \
+  DECL_FUNC (TYPE_SHORT, 26, 128)       \
+  DECL_FUNC (TYPE_SHORT, 27, 256)       \
+  DECL_FUNC (TYPE_SHORT, 28, 32768)       \
+  DECL_FUNC (TYPE_SHORT, 29, 65536)
+
+/* Finite numbers (except 2^16 in _Float16, making an inf).  */
+DECL_FINITE_FUNCS (h)
+
+/* min.  */
+DECL_FUNC (h, 01, __FLT16_MIN__)
+
+/* inf.  */
+DECL_FUNC (h, 30, __builtin_inff16 ())
+
+/* nan.  */
+DECL_FUNC (h, 31, __builtin_nanf16 (""))
+
+/* { dg-final { scan-assembler-not "fli\\.h\t" } } */
diff --git a/gcc/testsuite/gcc.target/riscv/zfa-fli-7.c b/gcc/testsuite/gcc.target/riscv/zfa-fli-7.c
new file mode 100644 (file)
index 0000000..912b2bf
--- /dev/null
@@ -0,0 +1,30 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64imfd_zfa_zfh -mabi=lp64d"  { target { rv64 } } } */
+/* { dg-options "-march=rv32imfd_zfa_zfh -mabi=ilp32d" { target { rv32 } } } */
+/* { dg-skip-if "" { *-*-* } {"-O0" "-Og" "-Oz"} } */
+
+/* Canonical NaN is, positive, quiet NaN with zero payload.  */
+
+#define TYPE_h _Float16
+#define TYPE_s float
+#define TYPE_d double
+
+#define DECL_TYPE(TYPE_SHORT) TYPE_##TYPE_SHORT
+
+#define DECL_FUNC(TYPE_SHORT, N, VALUE)       \
+  DECL_TYPE (TYPE_SHORT) const_##TYPE_SHORT##_##N (void)       \
+    {       \
+      return VALUE;       \
+    }
+
+/* Canonical NaN.  */
+DECL_FUNC (h, 1, __builtin_nanf16 (""))
+DECL_FUNC (s, 1, __builtin_nanf (""))
+DECL_FUNC (d, 1, __builtin_nan (""))
+DECL_FUNC (h, 2, __builtin_nanf16 ("0"))
+DECL_FUNC (s, 2, __builtin_nanf ("0"))
+DECL_FUNC (d, 2, __builtin_nan ("0"))
+
+/* { dg-final { scan-assembler-times "fli\\.h\tfa0,nan\n" 2 } } */
+/* { dg-final { scan-assembler-times "fli\\.s\tfa0,nan\n" 2 } } */
+/* { dg-final { scan-assembler-times "fli\\.d\tfa0,nan\n" 2 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/zfa-fli-8.c b/gcc/testsuite/gcc.target/riscv/zfa-fli-8.c
new file mode 100644 (file)
index 0000000..96a53fd
--- /dev/null
@@ -0,0 +1,39 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64imfd_zfa_zfh -mabi=lp64d"  { target { rv64 } } } */
+/* { dg-options "-march=rv32imfd_zfa_zfh -mabi=ilp32d" { target { rv32 } } } */
+/* { dg-skip-if "" { *-*-* } {"-O0" "-Og" "-Oz"} } */
+
+/* Canonical NaN is, positive, quiet NaN with zero payload.  */
+
+#define TYPE_h _Float16
+#define TYPE_s float
+#define TYPE_d double
+
+#define DECL_TYPE(TYPE_SHORT) TYPE_##TYPE_SHORT
+
+#define DECL_FUNC(TYPE_SHORT, N, VALUE)       \
+  DECL_TYPE (TYPE_SHORT) const_##TYPE_SHORT##_##N (void)       \
+    {       \
+      return VALUE;       \
+    }
+
+/* Non-canonical NaN.  */
+DECL_FUNC (h, 1, __builtin_nansf16 (""))
+DECL_FUNC (s, 1, __builtin_nansf (""))
+DECL_FUNC (d, 1, __builtin_nans (""))
+DECL_FUNC (h, 2, __builtin_nansf16 ("0"))
+DECL_FUNC (s, 2, __builtin_nansf ("0"))
+DECL_FUNC (d, 2, __builtin_nans ("0"))
+DECL_FUNC (h, 3, __builtin_nanf16 ("1"))
+DECL_FUNC (s, 3, __builtin_nanf ("1"))
+DECL_FUNC (d, 3, __builtin_nan ("1"))
+DECL_FUNC (h, 4, __builtin_nansf16 ("1"))
+DECL_FUNC (s, 4, __builtin_nansf ("1"))
+DECL_FUNC (d, 4, __builtin_nans ("1"))
+
+/* Canonical NaN, negated (making it non-canonical).  */
+DECL_FUNC (h, 5, -__builtin_nanf16 (""))
+DECL_FUNC (s, 5, -__builtin_nanf (""))
+DECL_FUNC (d, 5, -__builtin_nan (""))
+
+/* { dg-final { scan-assembler-not "fli\\.\[hsd]\tfa0,nan\n" } } */
diff --git a/gcc/testsuite/gcc.target/riscv/zfa-fli-zfh.c b/gcc/testsuite/gcc.target/riscv/zfa-fli-zfh.c
new file mode 100644 (file)
index 0000000..05e2dcb
--- /dev/null
@@ -0,0 +1,42 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv32imafdc_zfa_zfh -mabi=ilp32d -O0" { target { rv32 } } } */
+/* { dg-options "-march=rv64imafdc_zfa_zfh -mabi=lp64d -O0" { target { rv64 } } } */
+
+void foo_float16 ()
+{
+  volatile _Float16 a;
+  a = -1.0;
+  a = 6.104e-5;
+  a = 1.0/(1 << 16);
+  a = 1.0/(1 << 15);
+  a = 1.0/(1 << 8);
+  a = 1.0/(1 << 7);
+  a = 1.0/(1 << 4);
+  a = 1.0/(1 << 3);
+  a = 1.0/(1 << 2);
+  a = 0.3125;
+  a = 0.375;
+  a = 0.4375;
+  a = 0.5;
+  a = 0.625;
+  a = 0.75;
+  a = 0.875;
+  a = 1.0;
+  a = 1.25;
+  a = 1.5;
+  a = 1.75;
+  a = 2.0;
+  a = 2.5;
+  a = 3.0;
+  a = 1.0*(1 << 2);
+  a = 1.0*(1 << 3);
+  a = 1.0*(1 << 4);
+  a = 1.0*(1 << 7);
+  a = 1.0*(1 << 8);
+  a = 1.0*(1 << 15);
+  a = 1.0*(1 << 16);
+  a = __builtin_inff16 ();
+  a = __builtin_nanf16 ("");
+}
+
+/* { dg-final { scan-assembler-times "fli.h" 32 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/zfa-fli.c b/gcc/testsuite/gcc.target/riscv/zfa-fli.c
new file mode 100644 (file)
index 0000000..e5c1e59
--- /dev/null
@@ -0,0 +1,80 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv32imafdc_zfa -mabi=ilp32d" { target { rv32 } } } */
+/* { dg-options "-march=rv64imafdc_zfa -mabi=lp64d" { target { rv64 } } } */
+
+void foo_float32 ()
+{
+  volatile float a;
+  a = -1.0;
+  a = 1.1754944e-38;
+  a = 1.0/(1 << 16);
+  a = 1.0/(1 << 15);
+  a = 1.0/(1 << 8);
+  a = 1.0/(1 << 7);
+  a = 1.0/(1 << 4);
+  a = 1.0/(1 << 3);
+  a = 1.0/(1 << 2);
+  a = 0.3125;
+  a = 0.375;
+  a = 0.4375;
+  a = 0.5;
+  a = 0.625;
+  a = 0.75;
+  a = 0.875;
+  a = 1.0;
+  a = 1.25;
+  a = 1.5;
+  a = 1.75;
+  a = 2.0;
+  a = 2.5;
+  a = 3.0;
+  a = 1.0*(1 << 2);
+  a = 1.0*(1 << 3);
+  a = 1.0*(1 << 4);
+  a = 1.0*(1 << 7);
+  a = 1.0*(1 << 8);
+  a = 1.0*(1 << 15);
+  a = 1.0*(1 << 16);
+  a = __builtin_inff ();
+  a = __builtin_nanf ("");
+}
+
+void foo_double64 ()
+{
+  volatile double a;
+  a = -1.0;
+  a = 2.2250738585072014e-308;
+  a = 1.0/(1 << 16);
+  a = 1.0/(1 << 15);
+  a = 1.0/(1 << 8);
+  a = 1.0/(1 << 7);
+  a = 1.0/(1 << 4);
+  a = 1.0/(1 << 3);
+  a = 1.0/(1 << 2);
+  a = 0.3125;
+  a = 0.375;
+  a = 0.4375;
+  a = 0.5;
+  a = 0.625;
+  a = 0.75;
+  a = 0.875;
+  a = 1.0;
+  a = 1.25;
+  a = 1.5;
+  a = 1.75;
+  a = 2.0;
+  a = 2.5;
+  a = 3.0;
+  a = 1.0*(1 << 2);
+  a = 1.0*(1 << 3);
+  a = 1.0*(1 << 4);
+  a = 1.0*(1 << 7);
+  a = 1.0*(1 << 8);
+  a = 1.0*(1 << 15);
+  a = 1.0*(1 << 16);
+  a = __builtin_inf ();
+  a = __builtin_nan ("");
+}
+
+/* { dg-final { scan-assembler-times "fli.s" 32 } } */
+/* { dg-final { scan-assembler-times "fli.d" 32 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/zfa-fmovh-fmovp.c b/gcc/testsuite/gcc.target/riscv/zfa-fmovh-fmovp.c
new file mode 100644 (file)
index 0000000..5a52adc
--- /dev/null
@@ -0,0 +1,10 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv32g_zfa -mabi=ilp32 -O0" } */
+
+double foo(long long a)
+{
+  return (double)(a + 3);
+}
+
+/* { dg-final { scan-assembler-times "fmvp.d.x" 1 } } */
+/* { dg-final { scan-assembler-times "fmvh.x.d" 1 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/zfa-fround.c b/gcc/testsuite/gcc.target/riscv/zfa-fround.c
new file mode 100644 (file)
index 0000000..0765334
--- /dev/null
@@ -0,0 +1,43 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv32imafdc_zfa -mabi=ilp32d" { target { rv32 } } } */
+/* { dg-options "-march=rv64imafdc_zfa -mabi=lp64d" { target { rv64 } } } */
+
+extern float a;
+extern double b;
+
+void foo (float *x, double *y)
+{
+  {
+    *x = __builtin_roundf (a);
+    *y = __builtin_round (b);
+  }
+  {
+    *x = __builtin_floorf (a);
+    *y = __builtin_floor (b);
+  }
+  {
+    *x = __builtin_ceilf (a);
+    *y = __builtin_ceil (b);
+  }
+  {
+    *x = __builtin_truncf (a);
+    *y = __builtin_trunc (b);
+  }
+  {
+    *x = __builtin_roundevenf (a);
+    *y = __builtin_roundeven (b);
+  }
+  {
+    *x = __builtin_nearbyintf (a);
+    *y = __builtin_nearbyint (b);
+  }
+  {
+    *x = __builtin_rintf (a);
+    *y = __builtin_rint (b);
+  }
+}
+
+/* { dg-final { scan-assembler-times "fround.s" 6 } } */
+/* { dg-final { scan-assembler-times "fround.d" 6 } } */
+/* { dg-final { scan-assembler-times "froundnx.s" 1 } } */
+/* { dg-final { scan-assembler-times "froundnx.d" 1 } } */