https://gcc.gnu.org/g:1bede52d8c4ba434a8f4786f84f85922cc0c6152

commit r16-6940-g1bede52d8c4ba434a8f4786f84f85922cc0c6152
Author: Jeff Law <[email protected]>
Date:   Tue Jan 20 15:03:28 2026 -0700

    [PR rtl-optimization/123380] Avoid creating bogus SUBREG in combine
    
    In this issue we try to call gen_rtx_SUBREG with arguments that will 
trigger an
    assertion failure.  In particular we're trying to create a paradoxical 
subreg
    of an HFmode object where the paradoxical is in DImode.  That's obviously a
    change in size.  validate_subreg returns false for that case, thus 
triggering
    the assertion.
    
    Like other cases in combine.cc and elsewhere we can check validate_subreg
    before we call gen_rtx_SUBREG and if validate_subreg returns false, we can
    return a safe value.  So that's all this patch does.
    
    Bootstrapped and regression tested on x86_64, also regression tested on
    riscv{32,64}-elf.  Pushing to the trunk.
    
            PR rtl-optimization/123380
    gcc/
            * combine.cc (gen_lowpart_for_combine): Don't try to create a
            paradoxical SUBREG if it's going to be rejected by validate_subreg.
    
    gcc/testsuite/
            * gcc.target/riscv/pr123380.c: New test.

Diff:
---
 gcc/combine.cc                            |  3 ++-
 gcc/testsuite/gcc.target/riscv/pr123380.c | 18 ++++++++++++++++++
 2 files changed, 20 insertions(+), 1 deletion(-)

diff --git a/gcc/combine.cc b/gcc/combine.cc
index 09e24347b342..573ed716ad63 100644
--- a/gcc/combine.cc
+++ b/gcc/combine.cc
@@ -11856,7 +11856,8 @@ gen_lowpart_for_combine (machine_mode omode, rtx x)
       /* If we want to refer to something bigger than the original memref,
         generate a paradoxical subreg instead.  That will force a reload
         of the original memref X.  */
-      if (paradoxical_subreg_p (omode, imode))
+      if (paradoxical_subreg_p (omode, imode)
+         && validate_subreg (omode, GET_MODE (x), x, 0))
        return gen_rtx_SUBREG (omode, x, 0);
 
       poly_int64 offset = byte_lowpart_offset (omode, imode);
diff --git a/gcc/testsuite/gcc.target/riscv/pr123380.c 
b/gcc/testsuite/gcc.target/riscv/pr123380.c
new file mode 100644
index 000000000000..1cbbc8436156
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/pr123380.c
@@ -0,0 +1,18 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gc -mabi=lp64d -O2" { target { rv64 } } } */
+/* { dg-options "-march=rv32gc -mabi=ilp32d -O2" { target { rv32 } } } */
+
+void *p;
+int d;
+char c;
+
+void
+foo (_Float16 *fp)
+{
+  _Float16 f = *fp;
+  do {
+    __builtin_strcat (p, 0);
+    __builtin_memmove (1 + (char *) &f, &f, 1);
+  } while (d);
+  c = f;
+}

Reply via email to