From: Christoph Müllner <christoph.muell...@vrull.eu>

The XTheadFmv ISA extension provides instructions to move
data between 32-bit GP registers and 64-bit FP registers.

gcc/ChangeLog:

        * config/riscv/constraints.md (TARGET_XTHEADFMV ? FP_REGS : NO_REGS)
        New constraint "th_f_fmv".
        (TARGET_XTHEADFMV ? GR_REGS : NO_REGS): New constraint
        "th_r_fmv".
        * config/riscv/riscv.cc (riscv_split_doubleword_move):
        Add split code for XTheadFmv.
        (riscv_secondary_memory_needed): XTheadFmv does not need
        secondary memory.
        * config/riscv/riscv.md: Add new UNSPEC_XTHEADFMV and
        UNSPEC_XTHEADFMV_HW. Add support for XTheadFmv to
        movdf_hardfloat_rv32.
        * config/riscv/thead.md (th_fmv_hw_w_x): New INSN.
        (th_fmv_x_w): New INSN.
        (th_fmv_x_hw): New INSN.

gcc/testsuite/ChangeLog:

        * gcc.target/riscv/xtheadfmv-fmv.c: New test.

Co-Developed-by: Xianmiao Qu <cooper...@linux.alibaba.com>
Signed-off-by: Xianmiao Qu <cooper...@linux.alibaba.com>
Signed-off-by: Christoph Müllner <christoph.muell...@vrull.eu>
---
 gcc/config/riscv/constraints.md               |  8 +++++
 gcc/config/riscv/riscv.cc                     | 25 ++++++++++++--
 gcc/config/riscv/riscv.md                     | 11 +++++--
 gcc/config/riscv/thead.md                     | 33 +++++++++++++++++++
 .../gcc.target/riscv/xtheadfmv-fmv.c          | 24 ++++++++++++++
 5 files changed, 95 insertions(+), 6 deletions(-)
 create mode 100644 gcc/testsuite/gcc.target/riscv/xtheadfmv-fmv.c

diff --git a/gcc/config/riscv/constraints.md b/gcc/config/riscv/constraints.md
index 51cffb2bcb6..f3b1af774e1 100644
--- a/gcc/config/riscv/constraints.md
+++ b/gcc/config/riscv/constraints.md
@@ -156,3 +156,11 @@ (define_constraint "Wdm"
   "Vector duplicate memory operand"
   (and (match_operand 0 "memory_operand")
        (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.")
diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc
index 21ec7a6225b..fc18ce2c766 100644
--- a/gcc/config/riscv/riscv.cc
+++ b/gcc/config/riscv/riscv.cc
@@ -2754,11 +2754,29 @@ riscv_split_64bit_move_p (rtx dest, rtx src)
 void
 riscv_split_doubleword_move (rtx dest, rtx src)
 {
-  rtx low_dest;
+  /* XTheadFmv has instructions for accessing the upper bits of a double.  */
+  if (!TARGET_64BIT && 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));
+         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));
+         return;
+       }
+    }
 
    /* The operation can be split into two normal moves.  Decide in
       which order to do them.  */
-   low_dest = riscv_subword (dest, false);
+   rtx low_dest = riscv_subword (dest, false);
    if (REG_P (low_dest) && reg_overlap_mentioned_p (low_dest, src))
      {
        riscv_emit_move (riscv_subword (dest, true), riscv_subword (src, true));
@@ -5752,7 +5770,8 @@ riscv_secondary_memory_needed (machine_mode mode, 
reg_class_t class1,
 {
   return (!riscv_v_ext_vector_mode_p (mode)
          && GET_MODE_SIZE (mode).to_constant () > UNITS_PER_WORD
-         && (class1 == FP_REGS) != (class2 == FP_REGS));
+         && (class1 == FP_REGS) != (class2 == FP_REGS)
+         && !TARGET_XTHEADFMV);
 }
 
 /* Implement TARGET_REGISTER_MOVE_COST.  */
diff --git a/gcc/config/riscv/riscv.md b/gcc/config/riscv/riscv.md
index 20506451e7c..ef6ae443059 100644
--- a/gcc/config/riscv/riscv.md
+++ b/gcc/config/riscv/riscv.md
@@ -100,6 +100,10 @@ (define_c_enum "unspecv" [
 
   ;; Zihintpause unspec
   UNSPECV_PAUSE
+
+  ;; XTheadFmv unspec
+  UNSPEC_XTHEADFMV
+  UNSPEC_XTHEADFMV_HW
 ])
 
 (define_constants
@@ -1836,16 +1840,17 @@ (define_expand "movdf"
     DONE;
 })
 
+
 ;; 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,  *r,*r,*m")
-       (match_operand:DF 1 "move_operand"         " f,G,m,f,G,*r*G,*m,*r"))]
+  [(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"))]
   "!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,move,load,store")
+  [(set_attr "move_type" 
"fmove,mtc,fpload,fpstore,store,mtc,mfc,move,load,store")
    (set_attr "mode" "DF")])
 
 (define_insn "*movdf_hardfloat_rv64"
diff --git a/gcc/config/riscv/thead.md b/gcc/config/riscv/thead.md
index d9cac15cc5f..d3e3644c73f 100644
--- a/gcc/config/riscv/thead.md
+++ b/gcc/config/riscv/thead.md
@@ -144,6 +144,39 @@ (define_insn "*th_cond_gpr_mov<GPR:mode><GPR2:mode>"
   [(set_attr "type" "condmove")
    (set_attr "mode" "<GPR:MODE>")])
 
+;; XTheadFmv
+
+;; In RV32, we lack fmv.x.d and fmv.d.x, but XTheadFmv has instructions
+;; that cover this case.
+
+(define_insn "th_fmv_hw_w_x"
+  [(set (match_operand:DF 0 "register_operand" "=f")
+       (unspec:DF [(match_operand:SI 1 "register_operand" "r")
+                (match_operand:SI 2 "register_operand" "r")]
+     UNSPEC_XTHEADFMV))]
+  "!TARGET_64BIT && TARGET_XTHEADFMV"
+  "fmv.w.x\t%0,%2\n\tth.fmv.hw.x\t%0,%1"
+  [(set_attr "move_type" "move")
+   (set_attr "mode" "DF")])
+
+(define_insn "th_fmv_x_w"
+  [(set (match_operand:SI 0 "register_operand" "=r")
+       (unspec:SI [(match_operand:DF 1 "register_operand" "f")]
+     UNSPEC_XTHEADFMV))]
+  "!TARGET_64BIT && TARGET_XTHEADFMV"
+  "fmv.x.w\t%0,%1"
+  [(set_attr "move_type" "move")
+   (set_attr "mode" "DF")])
+
+(define_insn "th_fmv_x_hw"
+  [(set (match_operand:SI 0 "register_operand" "=r")
+       (unspec:SI [(match_operand:DF 1 "register_operand" "f")]
+     UNSPEC_XTHEADFMV_HW))]
+  "!TARGET_64BIT && TARGET_XTHEADFMV"
+  "th.fmv.x.hw\t%0,%1"
+  [(set_attr "move_type" "move")
+   (set_attr "mode" "DF")])
+
 ;; XTheadMac
 
 (define_insn "*th_mula<mode>"
diff --git a/gcc/testsuite/gcc.target/riscv/xtheadfmv-fmv.c 
b/gcc/testsuite/gcc.target/riscv/xtheadfmv-fmv.c
new file mode 100644
index 00000000000..10d035e9e1d
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/xtheadfmv-fmv.c
@@ -0,0 +1,24 @@
+/* { dg-do compile { target { rv32 } } } */
+/* { dg-options "-march=rv32gc_xtheadfmv" } */
+/* { dg-skip-if "" { *-*-* } { "-O0" } } */
+
+double
+ll2d (long long ll)
+{
+  return *(double*)&ll;
+}
+
+long long
+d2ll (double d)
+{
+  return *(long long*)&d;
+}
+
+/* { dg-final { scan-assembler "fmv.w.x" } } */
+/* { dg-final { scan-assembler "th.fmv.hw.x" } } */
+/* { dg-final { scan-assembler "fmv.x.w" } } */
+/* { dg-final { scan-assembler "th.fmv.x.hw" } } */
+/* { dg-final { scan-assembler-not "sw" } } */
+/* { dg-final { scan-assembler-not "fld" } } */
+/* { dg-final { scan-assembler-not "fsd" } } */
+/* { dg-final { scan-assembler-not "lw" } } */
-- 
2.38.1

Reply via email to