aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard Biener <rguenther@suse.de>2024-08-02 13:49:34 +0200
committerRichard Biener <rguenth@gcc.gnu.org>2024-08-06 09:33:12 +0200
commit8f3d0c8c3dd02d94635517c68fd314cbceed8373 (patch)
tree05d5a9f1f54ef349905c2081588ba335aaaf9fb8
parent3592d3f8cc4b89ae508c747a46a626d73cb9616d (diff)
downloadgcc-8f3d0c8c3dd02d94635517c68fd314cbceed8373.zip
gcc-8f3d0c8c3dd02d94635517c68fd314cbceed8373.tar.gz
gcc-8f3d0c8c3dd02d94635517c68fd314cbceed8373.tar.bz2
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.
-rw-r--r--gcc/expmed.cc12
-rw-r--r--gcc/testsuite/gcc.dg/torture/pr111821.c9
2 files changed, 21 insertions, 0 deletions
diff --git a/gcc/expmed.cc b/gcc/expmed.cc
index 154964b..2ca93e3 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 0000000..eec6eed
--- /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;
+}