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*)≪ +} + +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