Hi,
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.
Regtested on rv64gcv_zvl512b.
Regards
Robin
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.
---
gcc/config/riscv/riscv.cc | 78 ++++++++++++-------
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, 93 insertions(+), 30 deletions(-)
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/pr127484.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/pr127547.c
diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc
index 49e7476b832..2840a8b3133 100644
--- a/gcc/config/riscv/riscv.cc
+++ b/gcc/config/riscv/riscv.cc
@@ -5324,23 +5324,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
@@ -5375,11 +5372,10 @@ spill_subreg_move (rtx dest, rtx src)
"view" in outer mode. We can only get here when handling
subreg-punned registers for which the subreg byte is 0. */
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)
@@ -5392,10 +5388,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);
@@ -5573,14 +5568,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;
}
@@ -5592,22 +5588,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));
}
}
@@ -13165,6 +13182,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 8420b3d29e7..0908078a6c4 100644
--- a/gcc/config/riscv/riscv.md
+++ b/gcc/config/riscv/riscv.md
@@ -2903,6 +2903,19 @@ (define_expand "movoi"
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 00000000000..f264d76303d
--- /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 00000000000..02ff46fc365
--- /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;
+}
--
2.55.0