Currently expand_constructor when it comes to BLKmode types, we store out
the constructor to memory. But for the zero case, we could just use `const_int 
0`
instead for types who are less than or equal to BITS_PER_WORD.
This is only valid if we expanding without a target.

This fixes the storing zeros of `char[3]` and `char[7]` into registers.

Boostrapped and tested on x86_64-linux-gnu.
Build and tested for aarch64-linux-gnu.

        PR middle-end/110459

gcc/ChangeLog:

        * expr.cc (expand_constructor): For expansion of `{}` without a target
        and the size is less than BITS_PER_WORD, just return the constant 0.

gcc/testsuite/ChangeLog:

        * g++.target/aarch64/array-return-1.C: New test.
        * g++.target/i386/array-return-1.C: New test.

Signed-off-by: Andrew Pinski <quic_apin...@quicinc.com>
---
 gcc/expr.cc                                   | 13 +++++++++++
 .../g++.target/aarch64/array-return-1.C       | 22 +++++++++++++++++++
 .../g++.target/i386/array-return-1.C          | 20 +++++++++++++++++
 3 files changed, 55 insertions(+)
 create mode 100644 gcc/testsuite/g++.target/aarch64/array-return-1.C
 create mode 100644 gcc/testsuite/g++.target/i386/array-return-1.C

diff --git a/gcc/expr.cc b/gcc/expr.cc
index b3b46a26626..a230847e8da 100644
--- a/gcc/expr.cc
+++ b/gcc/expr.cc
@@ -9412,6 +9412,19 @@ expand_constructor (tree exp, rtx target, enum 
expand_modifier modifier,
       return constructor;
     }
 
+  /* For expanding of `{}` (or all zeros) without a target
+     with a non addressable constant constructor which will
+     fit into an integral mode, just return the constant 0.  */
+  if (mode == BLKmode
+      && !TREE_ADDRESSABLE (exp)
+      && TREE_CONSTANT (exp)
+      && target == NULL_RTX
+      && modifier == EXPAND_NORMAL
+      && all_zeros_p (exp)
+      && tree_fits_uhwi_p (TYPE_SIZE (type))
+      && tree_to_uhwi (TYPE_SIZE (type)) <= BITS_PER_WORD)
+    return const0_rtx;
+
   /* If the CTOR is available in static storage and not mostly
      zeros and we can move it by pieces prefer to do so since
      that's usually more efficient than performing a series of
diff --git a/gcc/testsuite/g++.target/aarch64/array-return-1.C 
b/gcc/testsuite/g++.target/aarch64/array-return-1.C
new file mode 100644
index 00000000000..7c0aa480775
--- /dev/null
+++ b/gcc/testsuite/g++.target/aarch64/array-return-1.C
@@ -0,0 +1,22 @@
+// { dg-do compile }
+// { dg-options "-O2" }
+// { dg-final { check-function-bodies "**" "" "" { target { le } } } }
+
+// PR middle-end/110459
+
+/*
+**_Z7sample2c:
+**     and     w0, w0, 255
+**     ret
+*/
+
+struct array {
+    char data[4];
+};
+
+// There should be no adjustment to the stack
+// { dg-final { scan-assembler-not "sp, sp," } }
+auto sample2(char c) {
+  array buffer = {c, 0, 0, 0};
+  return buffer;
+}
diff --git a/gcc/testsuite/g++.target/i386/array-return-1.C 
b/gcc/testsuite/g++.target/i386/array-return-1.C
new file mode 100644
index 00000000000..f11905d01e5
--- /dev/null
+++ b/gcc/testsuite/g++.target/i386/array-return-1.C
@@ -0,0 +1,20 @@
+// { dg-do compile }
+// { dg-options "-O2" }
+// { dg-final { check-function-bodies "**" "" "" { target { ! ia32 } } } }
+
+// PR middle-end/110459
+
+/*
+**_Z7sample2c:
+**     movzbl  %dil, %eax
+**     ret
+*/
+
+struct array {
+    char data[4];
+};
+
+array sample2(char c) {
+  array buffer = {c, 0, 0, 0};
+  return buffer;
+}
-- 
2.43.0

Reply via email to