From: Liao Shihua <shi...@iscas.ac.cn>

This Patch implements the Quad-precision Float extension for RISC-V, based on
Kito's work five years ago in 
https://github.com/riscvarchive/riscv-gcc/tree/q-ext

Co-authored-by: Kito Chen <kito.ch...@gmail.com>

gcc/ChangeLog:

        * config/riscv/iterators.md (fsd): Add TF mode to ANYF and ANYLSF 
iterators.
        * config/riscv/riscv-c.cc (riscv_cpu_cpp_builtins): Handle 
__riscv_float_abi_quad.
        * config/riscv/riscv-d.cc (riscv_d_handle_target_float_abi): Handle 
"quad" float abi.
        * config/riscv/riscv-ext.def: Define 'q' extension.
        * config/riscv/riscv-ext.opt: 
        * config/riscv/riscv-opts.h (enum riscv_abi_type): Add ABI_ILP32Q and 
ABI_LP64Q.
        * config/riscv/riscv-protos.h (riscv_split_64bit_move_p): Rename to 
riscv_split_move_p.
        * config/riscv/riscv.cc (riscv_load_store_insns): Use 
riscv_split_move_p.
        (riscv_subword): Fix the calculation of BYTE.
        (riscv_split_64bit_move_p): Rename to riscv_split_move_p, and handle TF 
mode.
        (riscv_split_move_p):
        (riscv_output_move): Handle TF mode in move instructions.
        (riscv_emit_float_compare): Handle TF mode in float compare.
        (riscv_for_each_saved_reg): Handle TF mode in saved FPRs.
        * config/riscv/riscv.h (UNITS_PER_FP_REG): Add support for TF mode.
        (UNITS_PER_FP_ARG): Add support for TF mode.
        * config/riscv/riscv.md (trunctfsf2): New pattern for truncating TF to 
SF.
        (trunctfdf2): New pattern for truncating TF to DF.
        (extendsftf2): New pattern for extending SF to TF.
        (extenddftf2): New pattern for extending DF to TF.
        (movtf): New expand for TF move.
        (*movtf_hardfloat_rv64): New insn for TF move in RV64.
        * config/riscv/riscv.opt: Add ABI_ILP32Q and ABI_LP64Q.
        * doc/riscv-ext.texi:

gcc/testsuite/ChangeLog:

        * gcc.target/riscv/arch-rvq.c: New test.
        * gcc.target/riscv/attribute-rvq.c: New test.
        * gcc.target/riscv/long-double-1.c: New test.
        * gcc.target/riscv/predef-rvq.c: New test.

---
 gcc/config/riscv/iterators.md                 | 12 ++--
 gcc/config/riscv/riscv-c.cc                   |  5 ++
 gcc/config/riscv/riscv-d.cc                   |  5 ++
 gcc/config/riscv/riscv-ext.def                | 15 +++++
 gcc/config/riscv/riscv-ext.opt                |  2 +
 gcc/config/riscv/riscv-opts.h                 |  4 +-
 gcc/config/riscv/riscv-protos.h               |  2 +-
 gcc/config/riscv/riscv.cc                     | 42 +++++++++---
 gcc/config/riscv/riscv.h                      | 13 ++--
 gcc/config/riscv/riscv.md                     | 67 ++++++++++++++++++-
 gcc/config/riscv/riscv.opt                    |  6 ++
 gcc/doc/riscv-ext.texi                        |  4 ++
 gcc/testsuite/gcc.target/riscv/arch-rvq.c     |  6 ++
 .../gcc.target/riscv/attribute-rvq.c          |  8 +++
 .../gcc.target/riscv/long-double-1.c          | 16 +++++
 gcc/testsuite/gcc.target/riscv/predef-rvq.c   | 34 ++++++++++
 16 files changed, 217 insertions(+), 24 deletions(-)
 create mode 100644 gcc/testsuite/gcc.target/riscv/arch-rvq.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/attribute-rvq.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/long-double-1.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/predef-rvq.c

diff --git a/gcc/config/riscv/iterators.md b/gcc/config/riscv/iterators.md
index d300224150..8abfe96785 100644
--- a/gcc/config/riscv/iterators.md
+++ b/gcc/config/riscv/iterators.md
@@ -107,12 +107,14 @@
 ;; Iterator for hardware-supported floating-point modes.
 (define_mode_iterator ANYF [(SF "TARGET_HARD_FLOAT || TARGET_ZFINX")
                            (DF "TARGET_DOUBLE_FLOAT || TARGET_ZDINX")
-                           (HF "TARGET_ZFH || TARGET_ZHINX")])
+                           (HF "TARGET_ZFH || TARGET_ZHINX")
+                               (TF "TARGET_QUAD_FLOAT")])
 
 ;; Iterator for hardware-supported load/store floating-point modes.
 (define_mode_iterator ANYLSF [(SF "TARGET_HARD_FLOAT || TARGET_ZFINX")
                              (DF "TARGET_DOUBLE_FLOAT || TARGET_ZDINX")
-                             (HF "TARGET_ZFHMIN || TARGET_ZHINXMIN")])
+                             (HF "TARGET_ZFHMIN || TARGET_ZHINXMIN")
+                                 (TF "TARGET_QUAD_FLOAT")])
 
 ;; Iterator for floating-point modes that can be loaded into X registers.
 (define_mode_iterator SOFTF [SF (DF "TARGET_64BIT") (HF "TARGET_ZFHMIN")])
@@ -143,7 +145,7 @@
 (define_mode_attr softload [(HF "lh") (SF "lw") (DF "ld")])
 
 ;; Instruction names for stores.
-(define_mode_attr store [(QI "sb") (HI "sh") (SI "sw") (DI "sd") (HF "fsh") 
(SF "fsw") (DF "fsd")])
+(define_mode_attr store [(QI "sb") (HI "sh") (SI "sw") (DI "sd") (HF "fsh") 
(SF "fsw") (DF "fsd") (TF "flq")])
 
 ;; Instruction names for FP stores from integer registers.
 (define_mode_attr softstore [(HF "sh") (SF "sw") (DF "sd")])
@@ -153,7 +155,7 @@
 (define_mode_attr reg [(SI "d") (DI "d") (CC "d")])
 
 ;; This attribute gives the format suffix for floating-point operations.
-(define_mode_attr fmt [(HF "h") (SF "s") (DF "d")])
+(define_mode_attr fmt [(HF "h") (SF "s") (DF "d") (TF "q")])
 
 ;; This attribute gives the integer suffix for floating-point conversions.
 (define_mode_attr ifmt [(SI "w") (DI "l")])
@@ -166,7 +168,7 @@
 
 ;; This attribute gives the upper-case mode name for one unit of a
 ;; floating-point mode.
-(define_mode_attr UNITMODE [(HF "HF") (SF "SF") (DF "DF")])
+(define_mode_attr UNITMODE [(HF "HF") (SF "SF") (DF "DF") (TF "TF")])
 
 ;; This attribute gives the integer mode that has half the size of
 ;; the controlling mode.
diff --git a/gcc/config/riscv/riscv-c.cc b/gcc/config/riscv/riscv-c.cc
index 4fc0528178..28c8e8622d 100644
--- a/gcc/config/riscv/riscv-c.cc
+++ b/gcc/config/riscv/riscv-c.cc
@@ -95,6 +95,11 @@ riscv_cpu_cpp_builtins (cpp_reader *pfile)
     case ABI_LP64D:
       builtin_define ("__riscv_float_abi_double");
       break;
+    
+    case ABI_ILP32Q:
+    case ABI_LP64Q:
+      builtin_define ("__riscv_float_abi_quad");
+      break;
     }
 
   switch (riscv_cmodel)
diff --git a/gcc/config/riscv/riscv-d.cc b/gcc/config/riscv/riscv-d.cc
index 9cce48d8ff..0fd7f47589 100644
--- a/gcc/config/riscv/riscv-d.cc
+++ b/gcc/config/riscv/riscv-d.cc
@@ -66,6 +66,11 @@ riscv_d_handle_target_float_abi (void)
     case ABI_LP64D:
       abi = "double";
       break;
+    
+    case ABI_ILP32Q:
+    case ABI_LP64Q:
+      abi = "quad";
+      break;
 
     default:
       abi = "";
diff --git a/gcc/config/riscv/riscv-ext.def b/gcc/config/riscv/riscv-ext.def
index d162fa47ef..dde30709b3 100644
--- a/gcc/config/riscv/riscv-ext.def
+++ b/gcc/config/riscv/riscv-ext.def
@@ -157,6 +157,21 @@ DEFINE_RISCV_EXT(
   /* BITMASK_BIT_POSITION*/ 3,
   /* EXTRA_EXTENSION_FLAGS */ 0)
 
+DEFINE_RISCV_EXT(
+  /* NAME */ q,
+  /* UPPERCASE_NAME */ QUAD_FLOAT,
+  /* FULL_NAME */ "Quad-precision floating-point extension",
+  /* DESC */ "",
+  /* URL */ ,
+  /* DEP_EXTS */ ({"d", "zicsr"}),
+  /* SUPPORTED_VERSIONS */ ({{2, 2, ISA_SPEC_CLASS_20191213},
+           {2, 2, ISA_SPEC_CLASS_20190608},
+           {2, 0, ISA_SPEC_CLASS_2P2}}),
+  /* FLAG_GROUP */ base,
+  /* BITMASK_GROUP_ID */ 0,
+  /* BITMASK_BIT_POSITION*/ 16,
+  /* EXTRA_EXTENSION_FLAGS */ 0)
+
 DEFINE_RISCV_EXT(
   /* NAME */ c,
   /* UPPERCASE_NAME */ RVC,
diff --git a/gcc/config/riscv/riscv-ext.opt b/gcc/config/riscv/riscv-ext.opt
index 2036c16498..4627ce202f 100644
--- a/gcc/config/riscv/riscv-ext.opt
+++ b/gcc/config/riscv/riscv-ext.opt
@@ -115,6 +115,8 @@ Mask(HARD_FLOAT) Var(riscv_base_subext)
 
 Mask(DOUBLE_FLOAT) Var(riscv_base_subext)
 
+Mask(QUAD_FLOAT) Var(riscv_base_subext)
+
 Mask(RVC) Var(riscv_base_subext)
 
 Mask(RVB) Var(riscv_base_subext)
diff --git a/gcc/config/riscv/riscv-opts.h b/gcc/config/riscv/riscv-opts.h
index 4e4e9d8930..372a513c3e 100644
--- a/gcc/config/riscv/riscv-opts.h
+++ b/gcc/config/riscv/riscv-opts.h
@@ -26,10 +26,12 @@ enum riscv_abi_type {
   ABI_ILP32E,
   ABI_ILP32F,
   ABI_ILP32D,
+  ABI_ILP32Q,
   ABI_LP64,
   ABI_LP64E,
   ABI_LP64F,
-  ABI_LP64D
+  ABI_LP64D,
+  ABI_LP64Q
 };
 extern enum riscv_abi_type riscv_abi;
 
diff --git a/gcc/config/riscv/riscv-protos.h b/gcc/config/riscv/riscv-protos.h
index 46b256d635..5bb1d81006 100644
--- a/gcc/config/riscv/riscv-protos.h
+++ b/gcc/config/riscv/riscv-protos.h
@@ -122,7 +122,7 @@ extern rtx riscv_unspec_address (rtx, enum 
riscv_symbol_type);
 extern void riscv_move_integer (rtx, rtx, HOST_WIDE_INT, machine_mode);
 extern bool riscv_legitimize_move (machine_mode, rtx, rtx);
 extern rtx riscv_subword (rtx, bool);
-extern bool riscv_split_64bit_move_p (rtx, rtx);
+extern bool riscv_split_move_p (rtx, rtx);
 extern void riscv_split_doubleword_move (rtx, rtx);
 extern const char *riscv_output_move (rtx, rtx);
 extern const char *riscv_output_return ();
diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc
index 07d40f459e..82cc6ad8d9 100644
--- a/gcc/config/riscv/riscv.cc
+++ b/gcc/config/riscv/riscv.cc
@@ -2661,7 +2661,7 @@ riscv_load_store_insns (rtx mem, rtx_insn *insn)
   else if (GET_MODE_BITSIZE (mode).to_constant () == 64)
     {
       set = single_set (insn);
-      if (set && !riscv_split_64bit_move_p (SET_DEST (set), SET_SRC (set)))
+      if (set && !riscv_split_move_p (SET_DEST (set), SET_SRC (set)))
        might_split_p = false;
     }
 
@@ -4721,12 +4721,14 @@ riscv_noce_conversion_profitable_p (rtx_insn *seq,
 rtx
 riscv_subword (rtx op, bool high_p)
 {
-  unsigned int byte = (high_p != BYTES_BIG_ENDIAN) ? UNITS_PER_WORD : 0;
+  unsigned int byte;
   machine_mode mode = GET_MODE (op);
 
   if (mode == VOIDmode)
     mode = TARGET_64BIT ? TImode : DImode;
 
+  byte = high_p ? (GET_MODE_SIZE (mode).to_constant () / 2 ) : 0;
+
   if (MEM_P (op))
     return adjust_address (op, word_mode, byte);
 
@@ -4736,12 +4738,14 @@ riscv_subword (rtx op, bool high_p)
   return simplify_gen_subreg (word_mode, op, mode, byte);
 }
 
-/* Return true if a 64-bit move from SRC to DEST should be split into two.  */
+/* Return true if move from SRC to DEST should be split into two.  */
 
 bool
-riscv_split_64bit_move_p (rtx dest, rtx src)
+riscv_split_move_p (rtx dest, rtx src)
 {
-  if (TARGET_64BIT)
+  machine_mode mode = GET_MODE (dest);
+
+  if (GET_MODE_SIZE (mode).to_constant () <= UNITS_PER_WORD)
     return false;
 
   /* Zilsd provides load/store with even-odd register pair. */
@@ -4763,7 +4767,7 @@ riscv_split_64bit_move_p (rtx dest, rtx src)
 
   /* Allow FPR <-> FPR and FPR <-> MEM moves, and permit the special case
      of zeroing an FPR with FCVT.D.W.  */
-  if (TARGET_DOUBLE_FLOAT
+  if (GET_MODE_SIZE (mode).to_constant () <= UNITS_PER_FP_REG
       && ((FP_REG_RTX_P (src) && FP_REG_RTX_P (dest))
          || (FP_REG_RTX_P (dest) && MEM_P (src))
          || (FP_REG_RTX_P (src) && MEM_P (dest))
@@ -4774,7 +4778,7 @@ riscv_split_64bit_move_p (rtx dest, rtx src)
 }
 
 /* Split a doubleword move from SRC to DEST.  On 32-bit targets,
-   this function handles 64-bit moves for which riscv_split_64bit_move_p
+   this function handles 64-bit moves for which riscv_split_move_p
    holds.  For 64-bit targets, this function handles 128-bit moves.  */
 
 void
@@ -4876,7 +4880,7 @@ riscv_output_move (rtx dest, rtx src)
   dbl_p = (GET_MODE_SIZE (mode).to_constant () == 8);
   width = GET_MODE_SIZE (mode).to_constant ();
 
-  if (dbl_p && riscv_split_64bit_move_p (dest, src))
+  if (dbl_p && riscv_split_move_p (dest, src))
     return "#";
 
   if (dest_code == REG && GP_REG_P (REGNO (dest)))
@@ -4893,6 +4897,8 @@ riscv_output_move (rtx dest, rtx src)
            return "fmv.x.s\t%0,%1";
          case 8:
            return "fmv.x.d\t%0,%1";
+    case 16:
+      return "fmv.x.q\t%0,%1";
          }
 
       if (src_code == MEM)
@@ -4954,6 +4960,13 @@ riscv_output_move (rtx dest, rtx src)
                /* in RV32, we can emulate fmv.d.x %0, x0 using fcvt.d.w */
                gcc_assert (src == CONST0_RTX (mode));
                return "fcvt.d.w\t%0,x0";
+        case 16:
+    gcc_assert (src == CONST0_RTX (mode));
+    /* In RV64, we can emulate fmv.q.x %0, x0 using fcvt.d.x.  */
+    if(TARGET_64BIT)
+      return "fmv.d.x\t%0,x0";
+    /* in RV32, we can emulate fmv.d.x %0, x0 using fcvt.d.w */
+    return "fcvt.d.w\t%0,x0";
              }
        }
       if (dest_code == MEM)
@@ -4978,6 +4991,8 @@ riscv_output_move (rtx dest, rtx src)
            return "fmv.s\t%0,%1";
          case 8:
            return "fmv.d\t%0,%1";
+    case 16:
+      return "fmv.q\t%0,%1";
          }
 
       if (dest_code == MEM)
@@ -4989,6 +5004,8 @@ riscv_output_move (rtx dest, rtx src)
            return "fsw\t%1,%0";
          case 8:
            return "fsd\t%1,%0";
+    case 16:
+      return "fsq\t%1,%0";
          }
     }
   if (dest_code == REG && FP_REG_P (REGNO (dest)))
@@ -5002,6 +5019,8 @@ riscv_output_move (rtx dest, rtx src)
            return "flw\t%0,%1";
          case 8:
            return "fld\t%0,%1";
+    case 16:
+      return "flq\t%0,%1";
          }
 
       if (src_code == CONST_DOUBLE && satisfies_constraint_zfli (src))
@@ -5339,6 +5358,10 @@ riscv_emit_float_compare (enum rtx_code *code, rtx *op0, 
rtx *op1,
        emit_insn (gen_f##CMP##_quiethfdi4 (*op0, cmp_op0, cmp_op1));   \
       else if (GET_MODE (cmp_op0) == HFmode)                           \
        emit_insn (gen_f##CMP##_quiethfsi4 (*op0, cmp_op0, cmp_op1));   \
+      else if (GET_MODE (cmp_op0) == TFmode && TARGET_64BIT)           \
+       emit_insn (gen_f##CMP##_quiettfdi4 (*op0, cmp_op0, cmp_op1));   \
+      else if (GET_MODE (cmp_op0) == TFmode)                           \
+       emit_insn (gen_f##CMP##_quiettfsi4 (*op0, cmp_op0, cmp_op1));   \
       else                                                             \
        gcc_unreachable ();                                             \
       *op1 = const0_rtx;                                               \
@@ -8526,7 +8549,8 @@ riscv_for_each_saved_reg (poly_int64 sp_offset, 
riscv_save_restore_fn fn,
     if (BITSET_P (cfun->machine->frame.fmask, regno - FP_REG_FIRST))
       {
        bool handle_reg = !cfun->machine->reg_is_wrapped_separately[regno];
-       machine_mode mode = TARGET_DOUBLE_FLOAT ? DFmode : SFmode;
+       machine_mode mode = TARGET_QUAD_FLOAT ? TFmode : 
+                      TARGET_DOUBLE_FLOAT ? DFmode : SFmode;
        unsigned int slot = (riscv_use_multi_push (&cfun->machine->frame))
                              ? CALLEE_SAVED_FREG_NUMBER (regno)
                              : num_masked_fp;
diff --git a/gcc/config/riscv/riscv.h b/gcc/config/riscv/riscv.h
index 9146571908..c46315a62e 100644
--- a/gcc/config/riscv/riscv.h
+++ b/gcc/config/riscv/riscv.h
@@ -173,17 +173,16 @@ ARCH_UNSET_CLEANUP_SPECS \
 #undef TARGET_MIN_ARITHMETIC_PRECISION
 #define TARGET_MIN_ARITHMETIC_PRECISION riscv_min_arithmetic_precision
 
-/* The `Q' extension is not yet supported.  */
-#define UNITS_PER_FP_REG (TARGET_DOUBLE_FLOAT ? 8 : 4)
+#define UNITS_PER_FP_REG (TARGET_QUAD_FLOAT ? 16 : TARGET_DOUBLE_FLOAT ? 8 : 4)
 /* Size per vector register. For VLEN = 32, size = poly (4, 4). Otherwise, 
size = poly (8, 8). */
 #define UNITS_PER_V_REG (riscv_vector_chunks * riscv_bytes_per_vector_chunk)
 
 /* The largest type that can be passed in floating-point registers.  */
-#define UNITS_PER_FP_ARG                                               \
-  ((riscv_abi == ABI_ILP32 || riscv_abi == ABI_ILP32E                  \
-    || riscv_abi == ABI_LP64 || riscv_abi == ABI_LP64E)                        
\
-   ? 0                                                                         
\
-   : ((riscv_abi == ABI_ILP32F || riscv_abi == ABI_LP64F) ? 4 : 8))
+#define UNITS_PER_FP_ARG                                       \
+  (riscv_abi == ABI_ILP32 || riscv_abi == ABI_LP64 ? 0 :       \
+   riscv_abi == ABI_ILP32E || riscv_abi == ABI_LP64E ? 0 :     \
+   riscv_abi == ABI_ILP32F || riscv_abi == ABI_LP64F ? 4 :     \
+   riscv_abi == ABI_ILP32D || riscv_abi == ABI_LP64D ? 8 : 16)
 
 /* Set the sizes of the core types.  */
 #define SHORT_TYPE_SIZE 16
diff --git a/gcc/config/riscv/riscv.md b/gcc/config/riscv/riscv.md
index 2a3a20e122..c1b4dd7be6 100644
--- a/gcc/config/riscv/riscv.md
+++ b/gcc/config/riscv/riscv.md
@@ -1874,6 +1874,22 @@
   [(set_attr "type" "fcvt")
    (set_attr "mode" "BF")])
 
+(define_insn "trunctfsf2"
+  [(set (match_operand:SF 0 "register_operand" "=f")
+        (float_truncate:SF (match_operand:TF 1 "register_operand" "f")))]
+  "TARGET_QUAD_FLOAT"
+  "fcvt.s.q\t%0,%1"
+  [(set_attr "type"     "fcvt")
+   (set_attr "mode"     "SF")])
+
+(define_insn "trunctfdf2"
+  [(set (match_operand:DF 0 "register_operand" "=f")
+        (float_truncate:DF (match_operand:TF 1 "register_operand" "f")))]
+  "TARGET_QUAD_FLOAT"
+  "fcvt.d.q\t%0,%1"
+  [(set_attr "type"     "fcvt")
+   (set_attr "mode"     "DF")])
+
 ;; The conversion of HF/DF/TF to BF needs to be done with SF if there is a
 ;; chance to generate at least one instruction, otherwise just using
 ;; libfunc __trunc[h|d|t]fbf2.
@@ -2086,6 +2102,22 @@
   [(set_attr "type" "fcvt")
    (set_attr "mode" "DF")])
 
+(define_insn "extendsftf2"
+  [(set (match_operand:TF 0 "register_operand" "=f")
+        (float_extend:TF (match_operand:SF 1 "register_operand" "f")))]
+  "TARGET_QUAD_FLOAT"
+  "fcvt.q.s\t%0,%1"
+  [(set_attr "type"     "fcvt")
+   (set_attr "mode"     "TF")])
+
+(define_insn "extenddftf2"
+  [(set (match_operand:TF 0 "register_operand" "=f")
+        (float_extend:TF (match_operand:DF 1 "register_operand" "f")))]
+  "TARGET_QUAD_FLOAT"
+  "fcvt.q.d\t%0,%1"
+  [(set_attr "type"     "fcvt")
+   (set_attr "mode"     "TF")])
+
 ;; 16-bit floating point moves
 (define_expand "mov<mode>"
   [(set (match_operand:HFBF 0 "")
@@ -2792,7 +2824,40 @@
   [(set (match_operand:MOVE64 0 "nonimmediate_operand")
        (match_operand:MOVE64 1 "move_operand"))]
   "reload_completed
-   && riscv_split_64bit_move_p (operands[0], operands[1])"
+   && riscv_split_move_p (operands[0], operands[1])"
+  [(const_int 0)]
+{
+  riscv_split_doubleword_move (operands[0], operands[1]);
+  DONE;
+})
+
+;; 128-bit floating point moves
+(define_expand "movtf"
+  [(set (match_operand:TF 0 "")
+        (match_operand:TF 1 ""))]
+  "TARGET_QUAD_FLOAT"
+{
+  if (riscv_legitimize_move (TFmode, operands[0], operands[1]))
+    DONE;
+})
+
+;; In RV64, we lack fmv.x.q and fmv.q.x.  Go through memory instead.
+;; (However, we can still use fcvt.q.w to zero a floating-point register.)
+(define_insn "*movtf_hardfloat_rv64"
+  [(set (match_operand:TF 0 "nonimmediate_operand" "=f,f,f,m,m,  *r,*r,*m")
+        (match_operand:TF 1 "move_operand"         " f,G,m,f,G,*r*G,*m,*r"))]
+  "TARGET_64BIT && TARGET_QUAD_FLOAT
+   && (register_operand (operands[0], TFmode)
+       || reg_or_0_operand (operands[1], TFmode))"
+  { return riscv_output_move (operands[0], operands[1]); }
+  [(set_attr "move_type" "fmove,mtc,fpload,fpstore,store,move,load,store")
+   (set_attr "mode" "TF")])
+
+(define_split
+  [(set (match_operand:TF 0 "nonimmediate_operand")
+        (match_operand:TF 1 "move_operand"))]
+  "reload_completed
+   && riscv_split_move_p (operands[0], operands[1])"
   [(const_int 0)]
 {
   riscv_split_doubleword_move (operands[0], operands[1]);
diff --git a/gcc/config/riscv/riscv.opt b/gcc/config/riscv/riscv.opt
index 6543fd1c4a..a6c97589a1 100644
--- a/gcc/config/riscv/riscv.opt
+++ b/gcc/config/riscv/riscv.opt
@@ -61,6 +61,9 @@ Enum(abi_type) String(ilp32f) Value(ABI_ILP32F)
 EnumValue
 Enum(abi_type) String(ilp32d) Value(ABI_ILP32D)
 
+EnumValue
+Enum(abi_type) String(ilp32q) Value(ABI_ILP32Q)
+
 EnumValue
 Enum(abi_type) String(lp64) Value(ABI_LP64)
 
@@ -73,6 +76,9 @@ Enum(abi_type) String(lp64f) Value(ABI_LP64F)
 EnumValue
 Enum(abi_type) String(lp64d) Value(ABI_LP64D)
 
+EnumValue
+Enum(abi_type) String(lp64q) Value(ABI_LP64Q)
+
 mfdiv
 Target Mask(FDIV)
 Use hardware floating-point divide and square root instructions.
diff --git a/gcc/doc/riscv-ext.texi b/gcc/doc/riscv-ext.texi
index 13056e73ba..29daa89f40 100644
--- a/gcc/doc/riscv-ext.texi
+++ b/gcc/doc/riscv-ext.texi
@@ -42,6 +42,10 @@
 @tab 2.0 2.2
 @tab Double-precision floating-point extension
 
+@item q
+@tab 2.0 2.2
+@tab Quad-precision floating-point extension
+
 @item c
 @tab 2.0
 @tab Compressed extension
diff --git a/gcc/testsuite/gcc.target/riscv/arch-rvq.c 
b/gcc/testsuite/gcc.target/riscv/arch-rvq.c
new file mode 100644
index 0000000000..3fd9cf04d3
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/arch-rvq.c
@@ -0,0 +1,6 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64i_q -mabi=lp64q" } */
+int foo()
+{
+}
+
diff --git a/gcc/testsuite/gcc.target/riscv/attribute-rvq.c 
b/gcc/testsuite/gcc.target/riscv/attribute-rvq.c
new file mode 100644
index 0000000000..f2a2d681eb
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/attribute-rvq.c
@@ -0,0 +1,8 @@
+/* { dg-do compile } */
+/* { dg-options "-mriscv-attribute -march=rv64iq -mabi=lp64q" } */
+
+void foo(){}
+
+/* { dg-final { scan-assembler ".attribute arch, 
\"rv64i2p1_f2p2_d2p2_q2p2_zicsr2p0\"" } } */
+
+
diff --git a/gcc/testsuite/gcc.target/riscv/long-double-1.c 
b/gcc/testsuite/gcc.target/riscv/long-double-1.c
new file mode 100644
index 0000000000..1ee990eb44
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/long-double-1.c
@@ -0,0 +1,16 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcq -mabi=lp64q -O0" } */
+
+long double foo(long double a, long double b)
+{
+  return a + b;
+}
+
+long double foo2(long double a, long double b)
+{
+  return a - b;
+}
+
+/* { dg-final { scan-assembler-times {\mfadd\.q\M} 1 } } */
+/* { dg-final { scan-assembler-times {\mfsub\.q\M} 1 } } */
+
diff --git a/gcc/testsuite/gcc.target/riscv/predef-rvq.c 
b/gcc/testsuite/gcc.target/riscv/predef-rvq.c
new file mode 100644
index 0000000000..24bf03045c
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/predef-rvq.c
@@ -0,0 +1,34 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64iq -mabi=lp64q" } */
+
+
+int main () {
+#if !defined(__riscv)
+#error "__riscv"
+#endif
+
+#if __riscv_xlen != 64
+#error "__riscv_xlen"
+#endif
+
+#if !defined(__riscv_fdiv)
+#error "__riscv_fdiv"
+#endif
+#if !defined(__riscv_fsqrt)
+#error "__riscv_fsqrt"
+#endif
+
+#if defined(__riscv_float_abi_soft)
+#error "__riscv_float_abi_soft"
+#endif
+#if defined(__riscv_float_abi_single)
+#error "__riscv_float_abi_single"
+#endif
+#if defined(__riscv_float_abi_double)
+#error "__riscv_float_abi_double"
+#endif
+#if !defined(__riscv_float_abi_quad)
+#error "__riscv_float_abi_double"
+#endif
+  return 0;
+}
-- 
2.51.0

Reply via email to