On Fri, Jul 4, 2025 at 2:37 PM Richard Sandiford
<richard.sandif...@arm.com> wrote:
>
> "H.J. Lu" <hjl.to...@gmail.com> writes:
> > On Thu, Jul 3, 2025 at 11:02 PM Richard Sandiford
> > <richard.sandif...@arm.com> wrote:
> >>
> >> "H.J. Lu" <hjl.to...@gmail.com> writes:
> >> > Since a backend may ignore user type alignment for arguments passed on
> >> > stack, update alignment for arguments passed on stack when copying MEM's
> >> > memory attributes.
> >> >
> >> > gcc/
> >> >
> >> > PR target/120839
> >> > * emit-rtl.cc (set_mem_attrs): Update alignment for argument on
> >> > stack.
> >> >
> >> > gcc/testsuite/
> >> >
> >> > PR target/120839
> >> > * gcc.target/i386/pr120839-1.c: New test.
> >> > * gcc.target/i386/pr120839-2.c: Likewise.
> >> >
> >> >
> >> > --
> >> > H.J.
> >> >
> >> > From 3f8a9bfb4beae47bfc0da20b517a5b3b06a1cbcc Mon Sep 17 00:00:00 2001
> >> > From: "H.J. Lu" <hjl.to...@gmail.com>
> >> > Date: Sat, 28 Jun 2025 06:27:25 +0800
> >> > Subject: [PATCH] Update alignment for argument on stack
> >> >
> >> > Since a backend may ignore user type alignment for arguments passed on
> >> > stack, update alignment for arguments passed on stack when copying MEM's
> >> > memory attributes.
> >> >
> >> > gcc/
> >> >
> >> >       PR target/120839
> >> >       * emit-rtl.cc (set_mem_attrs): Update alignment for argument on
> >> >       stack.
> >> >
> >> > gcc/testsuite/
> >> >
> >> >       PR target/120839
> >> >       * gcc.target/i386/pr120839-1.c: New test.
> >> >       * gcc.target/i386/pr120839-2.c: Likewise.
> >> >
> >> > Signed-off-by: H.J. Lu <hjl.to...@gmail.com>
> >> > ---
> >> >  gcc/emit-rtl.cc                            | 14 ++++++++++++++
> >> >  gcc/testsuite/gcc.target/i386/pr120839-1.c | 14 ++++++++++++++
> >> >  gcc/testsuite/gcc.target/i386/pr120839-2.c | 19 +++++++++++++++++++
> >> >  3 files changed, 47 insertions(+)
> >> >  create mode 100644 gcc/testsuite/gcc.target/i386/pr120839-1.c
> >> >  create mode 100644 gcc/testsuite/gcc.target/i386/pr120839-2.c
> >> >
> >> > diff --git a/gcc/emit-rtl.cc b/gcc/emit-rtl.cc
> >> > index f4fc92bb37a..0d1616361ca 100644
> >> > --- a/gcc/emit-rtl.cc
> >> > +++ b/gcc/emit-rtl.cc
> >> > @@ -389,6 +389,20 @@ set_mem_attrs (rtx mem, mem_attrs *attrs)
> >> >      {
> >> >        MEM_ATTRS (mem) = ggc_alloc<mem_attrs> ();
> >> >        memcpy (MEM_ATTRS (mem), attrs, sizeof (mem_attrs));
> >> > +      if (MEM_EXPR (mem))
> >> > +     {
> >> > +       tree base_address = get_base_address (MEM_EXPR (mem));
> >> > +       if (base_address && TREE_CODE (base_address) == PARM_DECL)
> >> > +         {
> >> > +           /* User alignment on type may be ignored for parameter
> >> > +              passed on stack.  */
> >> > +           tree type = TREE_TYPE (base_address);
> >> > +           unsigned int alignment
> >> > +             = targetm.calls.function_arg_boundary (TYPE_MODE (type),
> >> > +                                                    type);
> >> > +           set_mem_align (mem, alignment);
> >> > +         }
> >> > +     }
> >> >      }
> >> >  }
> >>
> >> This doesn't feel like the right place to address this.  set_mem_attrs
> >> is just supposed to install the attributes that it has been given,
> >> without second-guessing the contents.
> >>
> >> Where does the incorrect alignment ultimately come from?  (As in,
> >> which piece of code creates the MEM and fails to give it the correct
> >> alignment?)
> >
> > x86 has
> >
> > static unsigned int
> > ix86_function_arg_boundary (machine_mode mode, const_tree type)
> > {
> >   unsigned int align;
> >   if (type)
> >     {
> >       /* Since the main variant type is used for call, we convert it to
> >          the main variant type.  */
> >       type = TYPE_MAIN_VARIANT (type);
> >       align = TYPE_ALIGN (type);
> >       if (TYPE_EMPTY_P (type))
> >         return PARM_BOUNDARY;
> >     }
> >
> > Because of
> >
> > https://gcc.gnu.org/bugzilla/show_bug.cgi?id=120900
> >
> > for C,
> >
> > typedef struct {
> >   long double a, b
> > } c __attribute__((aligned(32)));
> >
> > when such a variable is passed on stack, its alignment
> > on stack is 16, not 32.  However, when set_mem_attrs
>                                     ^^^^^^^^^^^^^^^^^^
> > is called to set MEM_ALIGN for such a variable on stack,
>   ^^^^^^^^^^^^^^^^^^^^^^^^^^
> > it sets MEM_ALIGN to 32, instead of 16.
>
> But what I meant was: which piece of code calls set_mem_attrs
> to set MEM_ALIGN in this case?  The bug seems further up the
> call stack to me.
>

Breakpoint 1, set_mem_attrs (mem=0x7fffe9605510, attrs=0x7fffffffccd0)
    at /export/gnu/import/git/gitlab/x86-gcc-test/gcc/emit-rtl.cc:381
381   if (mem_attrs_eq_p (attrs, mode_mem_attrs[(int) GET_MODE (mem)]))
(gdb) bt
#0  set_mem_attrs (mem=0x7fffe9605510, attrs=0x7fffffffccd0)
    at /export/gnu/import/git/gitlab/x86-gcc-test/gcc/emit-rtl.cc:381
#1  0x00000000008096d3 in set_mem_attributes_minus_bitpos (ref=0x7fffe9605510,
    t=0x7fffe9810bb0, objectp=1, bitpos=...)
    at /export/gnu/import/git/gitlab/x86-gcc-test/gcc/emit-rtl.cc:2191
#2  0x0000000000809729 in set_mem_attributes (ref=0x7fffe9605510,
    t=0x7fffe9810bb0, objectp=1)
    at /export/gnu/import/git/gitlab/x86-gcc-test/gcc/emit-rtl.cc:2197
#3  0x000000000090d1a6 in assign_parm_find_stack_rtl (parm=0x7fffe9810bb0,
    data=0x7fffffffcee0)
    at /export/gnu/import/git/gitlab/x86-gcc-test/gcc/function.cc:2681
#4  0x0000000000911278 in assign_parms (fndecl=0x7fffe99d2900)
    at /export/gnu/import/git/gitlab/x86-gcc-test/gcc/function.cc:3691
#5  0x0000000000915be8 in expand_function_start (subr=0x7fffe99d2900)
    at /export/gnu/import/git/gitlab/x86-gcc-test/gcc/function.cc:5201
#6  0x00000000006c5b6b in (anonymous namespace)::pass_expand::execute (
    this=0x486c0e0, fun=0x7ffff7fbc190)
    at /export/gnu/import/git/gitlab/x86-gcc-test/gcc/cfgexpand.cc:7168
#7  0x0000000000d02703 in execute_one_pass (pass=0x486c0e0)
    at /export/gnu/import/git/gitlab/x86-gcc-test/gcc/passes.cc:2648
#8  0x0000000000d02afb in execute_pass_list_1 (pass=0x486c0e0)
    at /export/gnu/import/git/gitlab/x86-gcc-test/gcc/passes.cc:2757
...
(gdb) call debug (mem)
(mem/c:BLK (reg/f:DI 92 virtual-incoming-args) [0  A8])
(gdb) f 1
#1  0x00000000008096d3 in set_mem_attributes_minus_bitpos (ref=0x7fffe9605510,
    t=0x7fffe9810bb0, objectp=1, bitpos=...)
    at /export/gnu/import/git/gitlab/x86-gcc-test/gcc/emit-rtl.cc:2191
2191   set_mem_attrs (ref, &attrs);
(gdb) p attrs
$2 = {expr = 0x7fffe9810bb0, offset = {coeffs = {0}}, size = {coeffs = {32}},
  alias = 2, align = 256, addrspace = 0 '\000', offset_known_p = true,
  size_known_p = true}
(gdb)
Breakpoint 2, set_mem_attributes_minus_bitpos (ref=0x7fffe9605510,
    t=0x7fffe9810bb0, objectp=1, bitpos=...)
    at /export/gnu/import/git/gitlab/x86-gcc-test/gcc/emit-rtl.cc:2163
2163       get_object_alignment_1 (t, &obj_align, &obj_bitpos);
(gdb) next
2164       unsigned int diff_align = known_alignment (obj_bitpos - bitpos);
(gdb)
2165       if (diff_align != 0)
(gdb) p obj_align
$3 = 256
(gdb)
(gdb) next
2167       attrs.align = MAX (attrs.align, obj_align);
(gdb) p attrs.align
$4 = 256
(gdb)

256 is wrong only because

typedef struct {
  long double a;
  long double b;
} c __attribute__((aligned(32)));

is passed on stack.

The problems are in get_object_alignment_2 and set_mem_attributes_minus_bitpos.
Here is the v2 patch:

Since a backend may ignore user type alignment for arguments passed on
stack, call targetm.calls.function_arg_boundary to get alignment of
parameter on stack and don't increase it.

gcc/

PR target/120839
* builtins.cc (get_object_alignment_2): Call
targetm.calls.function_arg_boundary to get alignment of
parameter on stack.
* emit-rtl.cc (set_mem_attributes_minus_bitpos): Don't
increase alignment of parameter passed on stack.

gcc/testsuite/

PR target/120839
* gcc.target/i386/pr120839-1.c: New test.
* gcc.target/i386/pr120839-2.c: Likewise.

-- 
H.J.
From 2846d8dfcf3f03955f6a5bca700dcb89cbcea16e Mon Sep 17 00:00:00 2001
From: "H.J. Lu" <hjl.tools@gmail.com>
Date: Sat, 28 Jun 2025 06:27:25 +0800
Subject: [PATCH v2] Don't increase alignment of parameter on stack

Since a backend may ignore user type alignment for arguments passed on
stack, call targetm.calls.function_arg_boundary to get alignment of
parameter on stack and don't increase it.

gcc/

	PR target/120839
	* builtins.cc (get_object_alignment_2): Call
	targetm.calls.function_arg_boundary to get alignment of
	parameter on stack.
	* emit-rtl.cc (set_mem_attributes_minus_bitpos): Don't
	increase alignment of parameter passed on stack.

gcc/testsuite/

	PR target/120839
	* gcc.target/i386/pr120839-1.c: New test.
	* gcc.target/i386/pr120839-2.c: Likewise.

Signed-off-by: H.J. Lu <hjl.tools@gmail.com>
---
 gcc/builtins.cc                            | 11 ++++++++++-
 gcc/emit-rtl.cc                            |  8 +++++++-
 gcc/testsuite/gcc.target/i386/pr120839-1.c | 14 ++++++++++++++
 gcc/testsuite/gcc.target/i386/pr120839-2.c | 19 +++++++++++++++++++
 4 files changed, 50 insertions(+), 2 deletions(-)
 create mode 100644 gcc/testsuite/gcc.target/i386/pr120839-1.c
 create mode 100644 gcc/testsuite/gcc.target/i386/pr120839-2.c

diff --git a/gcc/builtins.cc b/gcc/builtins.cc
index a2ce3726810..9cecdd8a464 100644
--- a/gcc/builtins.cc
+++ b/gcc/builtins.cc
@@ -277,7 +277,16 @@ get_object_alignment_2 (tree exp, unsigned int *alignp,
     }
   else if (DECL_P (exp))
     {
-      align = DECL_ALIGN (exp);
+      if (TREE_CODE (exp) == PARM_DECL)
+	{
+	  /* Alignment of parameter passed on stack may be different
+	     from DECL_ALIGN.  */
+	  tree type = TREE_TYPE (exp);
+	  align = targetm.calls.function_arg_boundary
+	    (TYPE_MODE (type), type);
+	}
+      else
+	align = DECL_ALIGN (exp);
       known_alignment = true;
     }
   else if (TREE_CODE (exp) == INDIRECT_REF
diff --git a/gcc/emit-rtl.cc b/gcc/emit-rtl.cc
index f4fc92bb37a..234b05c7ef3 100644
--- a/gcc/emit-rtl.cc
+++ b/gcc/emit-rtl.cc
@@ -2092,6 +2092,7 @@ set_mem_attributes_minus_bitpos (rtx ref, tree t, int objectp,
 	MEM_KEEP_ALIAS_SET_P (ref) = 1;
 
       /* If this is a decl, set the attributes of the MEM from it.  */
+      bool parm_p = false;
       if (DECL_P (t))
 	{
 	  attrs.expr = t;
@@ -2099,6 +2100,7 @@ set_mem_attributes_minus_bitpos (rtx ref, tree t, int objectp,
 	  attrs.offset = 0;
 	  apply_bitpos = bitpos;
 	  new_size = DECL_SIZE_UNIT (t);
+	  parm_p = TREE_CODE (t) == PARM_DECL;
 	}
 
       /* ???  If we end up with a constant or a descriptor do not
@@ -2164,7 +2166,11 @@ set_mem_attributes_minus_bitpos (rtx ref, tree t, int objectp,
       unsigned int diff_align = known_alignment (obj_bitpos - bitpos);
       if (diff_align != 0)
 	obj_align = MIN (obj_align, diff_align);
-      attrs.align = MAX (attrs.align, obj_align);
+      /* Don't increase alignment of parameter passed on stack.  */
+      if (parm_p)
+	attrs.align = obj_align;
+      else
+	attrs.align = MAX (attrs.align, obj_align);
     }
 
   poly_uint64 const_size;
diff --git a/gcc/testsuite/gcc.target/i386/pr120839-1.c b/gcc/testsuite/gcc.target/i386/pr120839-1.c
new file mode 100644
index 00000000000..74fbf876330
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr120839-1.c
@@ -0,0 +1,14 @@
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+
+typedef struct
+{
+  long double a;
+  long double b;
+} c __attribute__((aligned(32)));
+extern double d;
+void
+bar (c f)
+{
+  d = f.a;
+}
diff --git a/gcc/testsuite/gcc.target/i386/pr120839-2.c b/gcc/testsuite/gcc.target/i386/pr120839-2.c
new file mode 100644
index 00000000000..e5b711c966f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr120839-2.c
@@ -0,0 +1,19 @@
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+/* { dg-final { scan-assembler-not "and\[lq\]?\[\\t \]*\\$-32,\[\\t \]*%\[re\]?sp" } } */
+
+typedef struct
+{
+  long double a;
+  long double b;
+} c __attribute__((aligned(32)));
+extern c x;
+extern double d;
+extern void bar (c);
+void
+foo (void)
+{
+  x.a = d;
+  x.b = d;
+  bar (x);
+}
-- 
2.50.0

Reply via email to