https://gcc.gnu.org/g:8f3d0c8c3dd02d94635517c68fd314cbceed8373

commit r15-2741-g8f3d0c8c3dd02d94635517c68fd314cbceed8373
Author: Richard Biener <rguent...@suse.de>
Date:   Fri Aug 2 13:49:34 2024 +0200

    middle-end/111821 - compile-time/memory-hog with large copy
    
    The following fixes a compile-time/memory-hog when performing a
    large aggregate copy to a small object allocated to a register.
    While store_bit_field_1 called by store_integral_bit_field will
    do nothign for accesses outside of the target the loop over the
    source in store_integral_bit_field will still code-generate
    the read parts for all words in the source.  The following copies
    the noop condition from store_bit_field_1 and terminates the
    loop when it runs forward or avoid code-generating the read parts
    when not.
    
            PR middle-end/111821
            * expmed.cc (store_integral_bit_field): Terminate the
            word-wise copy loop when we get out of the destination
            and do a forward copy.  Skip the word if it would be
            outside of the destination in case of a backward copy.
    
            * gcc.dg/torture/pr111821.c: New testcase.

Diff:
---
 gcc/expmed.cc                           | 12 ++++++++++++
 gcc/testsuite/gcc.dg/torture/pr111821.c |  9 +++++++++
 2 files changed, 21 insertions(+)

diff --git a/gcc/expmed.cc b/gcc/expmed.cc
index 154964bd0687..2ca93e30e8f2 100644
--- a/gcc/expmed.cc
+++ b/gcc/expmed.cc
@@ -986,6 +986,18 @@ store_integral_bit_field (rtx op0, opt_scalar_int_mode 
op0_mode,
            = backwards ^ reverse
              ? MAX ((int) bitsize - (i + 1) * BITS_PER_WORD, 0)
              : i * BITS_PER_WORD;
+
+         /* No further action is needed if the target is a register and if
+            this field lies completely outside that register.  */
+         if (REG_P (op0) && known_ge (bitnum + bit_offset,
+                                      GET_MODE_BITSIZE (GET_MODE (op0))))
+           {
+             if (backwards ^ reverse)
+               continue;
+             /* For forward operation we are finished.  */
+             return true;
+           }
+
          /* Starting word number in the value.  */
          const unsigned int wordnum
            = backwards
diff --git a/gcc/testsuite/gcc.dg/torture/pr111821.c 
b/gcc/testsuite/gcc.dg/torture/pr111821.c
new file mode 100644
index 000000000000..eec6eed6c8ed
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/torture/pr111821.c
@@ -0,0 +1,9 @@
+/* { dg-do compile } */
+
+typedef union { char a[__INT_MAX__ / 4]; } T;
+unsigned short f(const void *p)
+{
+  unsigned short v;
+  *(T *)(void *)(&v) = *(const T *)p;
+  return v;
+}

Reply via email to