A full-width bit-field store can use force_subreg to reinterpret a DImode
function address as V2SImode. validate_subreg accepts the resulting
SUBREG of a SYMBOL_REF, although it is not a general_operand, causing an
ICE during vregs.
Reject symbolic SUBREGs when either mode has multiple units. This makes
force_subreg materialize the address in a register first, while preserving
scalar and single-unit vector forms.
PR target/127060
gcc/ChangeLog:
* emit-rtl.cc (validate_subreg): Reject symbolic constants when either
mode has multiple units.
gcc/testsuite/ChangeLog:
* gcc.target/riscv/rvv/base/pr127060.c: New test.
Reported-by: XChy <[email protected]>
Signed-off-by: Jin Ma <[email protected]>
---
gcc/emit-rtl.cc | 10 ++++++++++
gcc/testsuite/gcc.target/riscv/rvv/base/pr127060.c | 14 ++++++++++++++
2 files changed, 24 insertions(+)
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/base/pr127060.c
diff --git a/gcc/emit-rtl.cc b/gcc/emit-rtl.cc
index 4a23eaefe02..b1205e80a38 100644
--- a/gcc/emit-rtl.cc
+++ b/gcc/emit-rtl.cc
@@ -924,6 +924,16 @@ validate_subreg (machine_mode omode, machine_mode imode,
if (maybe_ge (offset, isize))
return false;
+ /* Symbolic constants have no meaningful SUBREG interpretation when either
+ mode has multiple units. */
+ if (reg
+ && (GET_CODE (reg) == CONST
+ || SYMBOL_REF_P (reg)
+ || LABEL_REF_P (reg))
+ && (maybe_ne (GET_MODE_NUNITS (omode), 1)
+ || maybe_ne (GET_MODE_NUNITS (imode), 1)))
+ return false;
+
poly_uint64 regsize = REGMODE_NATURAL_SIZE (imode);
/* ??? This should not be here. Temporarily continue to allow word_mode
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/pr127060.c
b/gcc/testsuite/gcc.target/riscv/rvv/base/pr127060.c
new file mode 100644
index 00000000000..43fe619f8d4
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/pr127060.c
@@ -0,0 +1,14 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64d -O1" } */
+/* PR target/127060 */
+
+typedef int v2si __attribute__ ((vector_size (8)));
+
+int
+f (unsigned long i)
+{
+ v2si v;
+ int (*p) (unsigned long) = f;
+ __builtin_memcpy (&v, &p, sizeof (p));
+ return v[i & 1];
+}
--
2.52.0