https://gcc.gnu.org/g:3d79c978b53474d2b613fe3e28037393c8d037b0
commit r17-4722-g3d79c978b53474d2b613fe3e28037393c8d037b0 Author: Robin Dapp <[email protected]> Date: Mon Sep 21 22:24:25 2026 +0200 RISC-V: Spill more unsplittable moves [PR127484]. In the PRs we hit the same problem as before, just this time with a (subreg:TF (reg:V4SF)) pun on a 32-bit target and a complex int128. These are different quadword splits than before but they can be handled similarly. This patch extends riscv_subpart so it can deal with sub-parts of arbitrary modes. The new functionality is then used to move a spilled TFmode value in word-sized chunks. PR target/127484 PR target/127547 gcc/ChangeLog: * config/riscv/riscv.cc (riscv_subpart): Add parameters and handle more part sizes. (spill_subreg_move): Allow subreg bytes != 0. (riscv_split_quadword_move): Use riscv_subpart for TFmode. * config/riscv/riscv.md (movtf): Add. gcc/testsuite/ChangeLog: * gcc.target/riscv/rvv/autovec/pr127484.c: New test. * gcc.target/riscv/rvv/autovec/pr127547.c: New test. Diff: --- gcc/config/riscv/riscv.cc | 81 +++++++++++++--------- gcc/config/riscv/riscv.md | 13 ++++ .../gcc.target/riscv/rvv/autovec/pr127484.c | 19 +++++ .../gcc.target/riscv/rvv/autovec/pr127547.c | 13 ++++ 4 files changed, 94 insertions(+), 32 deletions(-) diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc index 87c24e5dcc15..ae3fd8e3d72b 100644 --- a/gcc/config/riscv/riscv.cc +++ b/gcc/config/riscv/riscv.cc @@ -5370,23 +5370,20 @@ riscv_subword (rtx op, bool high_p) return simplify_gen_subreg (word_mode, op, mode, byte); } -/* Same as riscv_subword, just only for OImode. */ +/* Similar to riscv_subword, but gets sub-part PART_IDX of mode PART_MODE + from OP (of mode MODE). */ static rtx -riscv_subpart (rtx op, bool high_p) +riscv_subpart (rtx op, machine_mode mode, scalar_mode part_mode, + poly_uint64 part_idx) { - unsigned int byte = (high_p != BYTES_BIG_ENDIAN) ? 16 : 0; - machine_mode mode = GET_MODE (op); - - if (mode == VOIDmode) - mode = OImode; - - gcc_assert (mode == OImode); + gcc_assert (multiple_p (GET_MODE_SIZE (mode), GET_MODE_SIZE (part_mode))); + poly_uint64 byte = part_idx * GET_MODE_SIZE (part_mode); if (MEM_P (op)) - return adjust_address (op, TImode, byte); + return adjust_address (op, part_mode, byte); - return simplify_gen_subreg (TImode, op, mode, byte); + return simplify_gen_subreg (part_mode, op, mode, byte); } /* Return true if OP is a subreg that we cannot split into words or false @@ -5418,14 +5415,12 @@ spill_subreg_move (rtx dest, rtx src) if (spill_src) { /* Get a stack slot of inner mode, move the inner reg to it and - "view" in outer mode. We can only get here when handling - subreg-punned registers for which the subreg byte is 0. */ + "view" in outer mode. */ rtx inner = SUBREG_REG (src); - gcc_assert (known_eq (SUBREG_BYTE (src), 0)); machine_mode mode_inner = GET_MODE (inner); rtx mem = assign_stack_temp (mode_inner, GET_MODE_SIZE (mode_inner)); emit_move_insn (mem, inner); - tmp_src = adjust_address (mem, GET_MODE (src), 0); + tmp_src = adjust_address (mem, GET_MODE (src), SUBREG_BYTE (src)); } if (!spill_dest) @@ -5438,10 +5433,9 @@ spill_subreg_move (rtx dest, rtx src) Then, view it as outer mode and move the source to it. Finally, store it in the inner subreg. */ rtx inner = SUBREG_REG (dest); - gcc_assert (known_eq (SUBREG_BYTE (dest), 0)); machine_mode mode_inner = GET_MODE (inner); rtx mem = assign_stack_temp (mode_inner, GET_MODE_SIZE (mode_inner)); - rtx mem_outer = adjust_address (mem, GET_MODE (dest), 0); + rtx mem_outer = adjust_address (mem, GET_MODE (dest), SUBREG_BYTE (dest)); if (maybe_gt (GET_MODE_SIZE (mode_inner), GET_MODE_SIZE (GET_MODE (dest)))) emit_move_insn (mem, inner); emit_move_insn (mem_outer, tmp_src); @@ -5619,14 +5613,15 @@ riscv_split_doubleword_move (rtx dest, rtx src) void riscv_split_quadword_move (rtx dest, rtx src) { - gcc_assert (GET_MODE (dest) == OImode); + gcc_assert (GET_MODE (dest) == OImode || GET_MODE (dest) == TFmode); gcc_assert (!BYTES_BIG_ENDIAN); /* Nothing to do for highwords of paradoxical subregs. */ if (paradoxical_subreg_p (dest) || paradoxical_subreg_p (src)) { - riscv_split_doubleword_move (riscv_subpart (dest, false), - riscv_subpart (src, false)); + gcc_assert (GET_MODE (dest) == OImode); + riscv_split_doubleword_move (riscv_subpart (dest, OImode, TImode, 0), + riscv_subpart (src, OImode, TImode, 0)); return; } @@ -5638,22 +5633,43 @@ riscv_split_quadword_move (rtx dest, rtx src) return; } - /* Split into TImode hi/lo parts and hand off to - riscv_split_doubleword_move. */ - rtx src_lo = riscv_subpart (src, false); - rtx dest_lo = riscv_subpart (dest, false); - rtx src_hi = riscv_subpart (src, true); - rtx dest_hi = riscv_subpart (dest, true); - - if (reg_overlap_mentioned_p (dest_lo, src)) + if (GET_MODE (dest) == OImode) { - riscv_split_doubleword_move (dest_hi, src_hi); - riscv_split_doubleword_move (dest_lo, src_lo); + /* Split into TImode hi/lo parts and hand off to + riscv_split_doubleword_move. */ + rtx src_lo = riscv_subpart (src, OImode, TImode, 0); + rtx dest_lo = riscv_subpart (dest, OImode, TImode, 0); + rtx src_hi = riscv_subpart (src, OImode, TImode, 1); + rtx dest_hi = riscv_subpart (dest, OImode, TImode, 1); + + if (reg_overlap_mentioned_p (dest_lo, src)) + { + riscv_split_doubleword_move (dest_hi, src_hi); + riscv_split_doubleword_move (dest_lo, src_lo); + } + else + { + riscv_split_doubleword_move (dest_lo, src_lo); + riscv_split_doubleword_move (dest_hi, src_hi); + } } else { - riscv_split_doubleword_move (dest_lo, src_lo); - riscv_split_doubleword_move (dest_hi, src_hi); + /* Once we are here, we can work with SRC and DEST by + either building a subreg or adjusting the memory slot. */ + gcc_assert (GET_MODE (dest) == TFmode && !TARGET_64BIT); + rtx first_part = riscv_subpart (dest, TFmode, word_mode, 0); + bool overlap_p = REG_P (first_part) + && reg_overlap_mentioned_p (first_part, src); + + if (!overlap_p) + for (int i = 0; i < 4; i++) + emit_move_insn (riscv_subpart (dest, TFmode, word_mode, i), + riscv_subpart (src, TFmode, word_mode, i)); + else + for (int i = 3; i >= 0; i--) + emit_move_insn (riscv_subpart (dest, TFmode, word_mode, i), + riscv_subpart (src, TFmode, word_mode, i)); } } @@ -13211,6 +13227,7 @@ static bool riscv_can_change_mode_class (machine_mode from, machine_mode to, reg_class_t rclass) { + /* ??? TODO prohibit scalar-vector pun e.g. (subreg:TI (reg:V4SI )). */ /* We have RVV VLS modes and VLA modes sharing same REG_CLASS. In 'cprop_hardreg' stage, we will try to do hard reg copy propagation between wider mode (FROM) and narrow mode (TO). diff --git a/gcc/config/riscv/riscv.md b/gcc/config/riscv/riscv.md index 2f4a3686b70f..cfac4c960bf1 100644 --- a/gcc/config/riscv/riscv.md +++ b/gcc/config/riscv/riscv.md @@ -2903,6 +2903,19 @@ DONE; }) +;; And TFmode. +(define_expand "movtf" + [(set (match_operand:TF 0 "nonimmediate_operand") + (match_operand:TF 1 "general_operand"))] + "" +{ + if (TARGET_64BIT) + riscv_split_doubleword_move (operands[0], operands[1]); + else + riscv_split_quadword_move (operands[0], operands[1]); + DONE; +}) + (define_expand "cmpmemsi" [(parallel [(set (match_operand:SI 0) (compare:SI (match_operand:BLK 1) diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/pr127484.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/pr127484.c new file mode 100644 index 000000000000..f264d76303d5 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/pr127484.c @@ -0,0 +1,19 @@ +/* { dg-do compile } */ +/* { dg-options "-O -march=rv32gcv -mabi=ilp32d" } */ + +typedef __attribute__((__vector_size__(16))) float V; + +union { + long double d; + V v; +} u; + +float f; +char c; + +void +foo() +{ + u.v -= f; + c *= u.d -= 0; +} diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/pr127547.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/pr127547.c new file mode 100644 index 000000000000..02ff46fc365e --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/pr127547.c @@ -0,0 +1,13 @@ +/* { dg-do compile } */ +/* { dg-options "-O -march=rv64gcv -mabi=lp64d" } */ + +typedef _Complex __int128 V; +typedef __attribute__((__vector_size__(32))) short W; + +_Complex float f; + +void +foo(W w) +{ + f *= *(V *)&w; +}
