[gcc r16-9383] PR middle-end/124637: Fix passing padded constant structs in registers on big-endian targets

Richard Biener via Gcc-cvs <[email protected]>
Newsgroups gmane.comp.gcc.cvs
Message-ID <[email protected]>
https://gcc.gnu.org/g:b9fe0227183712d5ea65d58bf127f95bfd51eaea

commit r16-9383-gb9fe0227183712d5ea65d58bf127f95bfd51eaea
Author: Roger Sayle <[email protected]>
Date:   Fri May 8 21:06:54 2026 +0100

    PR middle-end/124637: Fix passing padded constant structs in registers on big-endian targets
    
    This patch resolves PR middle-end/124637, a wrong code regression when
    passing a struct as a register on big-endian targets.  On big-endian
    targets, store_constructor fills fields from the most significant bits,
    so for structs narrower than word size, any padding is incorrectly
    placed in the least significant bytes.  This issue is fixed (on
    affected targets) by using a (unsigned) right shift on the value
    determined by store_constructor to correctly align the structure in
    the least significant bytes, and place the padding in the high bits.
    
    Many thanks to Manjunath Matti for testing this patch on real hardware,
    and Drea Pinski for reviewing/approving it.  The new test case may be
    a little fragile, but currently "works for me".  Please feel free to
    tweak it for powerpc variants/environments I've not consider/encountered.
    
    2026-05-08  Roger Sayle  <[email protected]>
    
    gcc/ChangeLog
            PR middle-end/124637
            * calls.cc (load_register_parameters): If using store_constructor
            to place a constant structure in a register, use a right shift to
            align the structure/padding if required on big-endian targets.
    
    gcc/testsuite/ChangeLog
            PR middle-end/124637
            * gcc.target/powerpc/pr124637.c: New test case.
    
    (cherry picked from commit d28460bfcff89064d1a991f4532337b997d7e102)

Diff:
---
 gcc/calls.cc                                | 14 ++++++++++++--
 gcc/testsuite/gcc.target/powerpc/pr124637.c | 26 ++++++++++++++++++++++++++
 2 files changed, 38 insertions(+), 2 deletions(-)

diff --git a/gcc/calls.cc b/gcc/calls.cc
index 4cdc2361a4bf..d491a4146115 100644
--- a/gcc/calls.cc
+++ b/gcc/calls.cc
@@ -2252,10 +2252,20 @@ load_register_parameters (struct arg_data *args, int num_actuals,
 		   && !TREE_SIDE_EFFECTS (tree_value)
 		   && immediate_const_ctor_p (DECL_INITIAL (tree_value)))
 	    {
+	      HOST_WIDE_INT size = int_expr_size (DECL_INITIAL (tree_value));
 	      rtx target = gen_reg_rtx (word_mode);
 	      store_constructor (DECL_INITIAL (tree_value), target, 0,
-				 int_expr_size (DECL_INITIAL (tree_value)),
-				 false);
+				 size, false);
+	      /* On big-endian targets, store_constructor places fields
+		 from the MSB, which places any padding bits in the least
+		 significant bytes.  If required, use a logical right shift
+		 to place things where expected in a register parameter.  */
+	      if (BYTES_BIG_ENDIAN
+		  && size < UNITS_PER_WORD
+		  && args[i].locate.where_pad == PAD_DOWNWARD)
+		target = expand_shift (RSHIFT_EXPR, word_mode, target,
+				       (UNITS_PER_WORD - size) * BITS_PER_UNIT,
+				       NULL_RTX, 1);
 	      reg = gen_rtx_REG (word_mode, REGNO (reg));
 	      emit_move_insn (reg, target);
 	    }
diff --git a/gcc/testsuite/gcc.target/powerpc/pr124637.c b/gcc/testsuite/gcc.target/powerpc/pr124637.c
new file mode 100644
index 000000000000..f38c7fa71269
--- /dev/null
+++ b/gcc/testsuite/gcc.target/powerpc/pr124637.c
@@ -0,0 +1,26 @@
+/* { dg-do compile { target { powerpc64-*-* } } } */
+/* { dg-options "-O2 -m64 -mbig-endian" } */
+
+typedef struct {
+    unsigned short a;
+    unsigned short b;
+    unsigned short c;
+} S_t;
+
+static const S_t m1 = { 0x20, 1, 1 };
+
+void ext(S_t r);
+void foo() { ext(m1); }
+
+/* Apologies in advance that these may be a little fragile.  */
+
+/* { dg-final { scan-assembler "lis 3,0x20" } } */
+/* { dg-final { scan-assembler "ori 3,3,0x1" } } */
+/* { dg-final { scan-assembler "sldi 3,3,16" } } */
+/* { dg-final { scan-assembler "ori 3,3,0x1" } } */
+
+/* { dg-final { scan-assembler-not "lis 9,0x20" } } */
+/* { dg-final { scan-assembler-not "ori 9,9,0x1" } } */
+/* { dg-final { scan-assembler-not "lis 3,0x1" } } */
+/* { dg-final { scan-assembler-not "rldimi 3,9,32,0" } } */
+
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.