On Tue, Jul 21, 2026 at 3:10 PM Sam James <[email protected]> wrote:
>
> "H.J. Lu" <[email protected]> writes:
>
> > commit b4c215b36d63e1c264d8c1bd5d34f9aef1bb8463
> > Author: H.J. Lu <[email protected]>
> > Date:   Sat Jun 28 06:27:25 2025 +0800
> >
> >     Adjust check for addressable misaligned stack argument
> >
> > ignores arguments passed on stack since caller is responsible to align
> > the outgoing stack for arguments passed on stack.  However, callee may
> > spill a register argument:
> >
> > (set (mem/c:V2DI (plus:DI (reg/f:DI 7 sp)
> > (const_int -16 [0xfffffffffffffff0])) [4 a1+0 S16 A128])
> >      (reg:V2DI 20 xmm0 [ a1 ]))
> >
> > Update ix86_argument_passed_on_stack_p to check spill of register argument
> > by callee.
> >
> > gcc/
> >
> > PR target/126320
> > * config/i386/i386.cc (ix86_spill_register_argument_p): New
> > function.
> > (ix86_argument_passed_on_stack_p): Add a pattern argument.  Call
> > ix86_spill_register_argument_p to check spill of register argument
> > by callee.
> > (ix86_update_stack_alignment): Pass pat to
> > ix86_argument_passed_on_stack_p.
> >
> > gcc/testsuite/
> >
> > PR target/126320
> > * gcc.target/i386/pr126320.c: New test.
>
> IMO for tests of this shape where we do builtin_cpu_supports, we should
> build the file without -march, but use the target attribute on the
> called function. It is paranoid but it means we don't have a lot of pain
> if (somehow) we use other instructions in main, and it sets a good
> example for copying.

Good point.  Here is the v2 patch without -mavx2.   -march=x86-64
is needed to enable SSE register parameter passing.

-- 
H.J.
From d81ef5776fcc2a96982f2b196c1fb27c68519a48 Mon Sep 17 00:00:00 2001
From: "H.J. Lu" <[email protected]>
Date: Mon, 20 Jul 2026 07:57:31 +0800
Subject: [PATCH v2] x86: Check register argument spill by callee

commit b4c215b36d63e1c264d8c1bd5d34f9aef1bb8463
Author: H.J. Lu <[email protected]>
Date:   Sat Jun 28 06:27:25 2025 +0800

    Adjust check for addressable misaligned stack argument

ignores arguments passed on stack since caller is responsible to align
the outgoing stack for arguments passed on stack.  However, callee may
spill a register argument:

(set (mem/c:V2DI (plus:DI (reg/f:DI 7 sp)
	(const_int -16 [0xfffffffffffffff0])) [4 a1+0 S16 A128])
     (reg:V2DI 20 xmm0 [ a1 ]))

Update ix86_argument_passed_on_stack_p to check spill of register argument
by callee.

gcc/

	PR target/126320
	* config/i386/i386.cc (ix86_spill_register_argument_p): New
	function.
	(ix86_argument_passed_on_stack_p): Add a pattern argument.  Call
	ix86_spill_register_argument_p to check spill of register argument
	by callee.
	(ix86_update_stack_alignment): Pass pat to
	ix86_argument_passed_on_stack_p.

gcc/testsuite/

	PR target/126320
	* gcc.target/i386/pr126320.c: New test.

Signed-off-by: H.J. Lu <[email protected]>
---
 gcc/config/i386/i386.cc                  | 63 +++++++++++++++++++++---
 gcc/testsuite/gcc.target/i386/pr126320.c | 45 +++++++++++++++++
 2 files changed, 101 insertions(+), 7 deletions(-)
 create mode 100644 gcc/testsuite/gcc.target/i386/pr126320.c

diff --git a/gcc/config/i386/i386.cc b/gcc/config/i386/i386.cc
index fd16dd441c1..094f224a20c 100644
--- a/gcc/config/i386/i386.cc
+++ b/gcc/config/i386/i386.cc
@@ -8609,18 +8609,67 @@ struct stack_access_data
   unsigned int *stack_alignment;
 };
 
-/* Return true if OP references an argument passed on stack.  */
+/* Return true if SET is a register argument spill to the stack operand
+   OP with base address BASE.  */
 
 static bool
-ix86_argument_passed_on_stack_p (const_rtx op)
+ix86_spill_register_argument_p (const_rtx set, const_rtx op, tree base)
+{
+  rtx src = SET_SRC (set);
+
+  /* Return true if source isn't a hard register.  Callee can read from
+     or write to argument passed on stack by caller.  */
+  if (!REG_P (src) || !HARD_REGISTER_P (src))
+    return false;
+
+  rtx dest = SET_DEST (set);
+  tree reg_expr = REG_EXPR (src);
+
+  /* If both the stack operand, which also is the destination of PAT,
+     and the register source of PAT point to the same argument, PAT
+     spills the register argument:
+
+     (set (mem/c:V2DI (plus:DI (reg/f:DI 7 sp)
+		(const_int -16 [0xfffffffffffffff0])) [4 a1+0 S16 A128])
+	  (reg:V2DI 20 xmm0 [ a1 ]))
+     */
+  return dest == op && reg_expr == base;
+}
+
+/* Return true if OP, found in instruction PAT, references an argument
+   passed on stack by the caller.  */
+
+static bool
+ix86_argument_passed_on_stack_p (const_rtx op, const_rtx pat)
 {
   tree mem_expr = MEM_EXPR (op);
-  if (mem_expr)
+  if (!mem_expr)
+    return false;
+
+  tree var = get_base_address (mem_expr);
+  if (TREE_CODE (var) != PARM_DECL)
+    return false;
+
+  /* The stack operand for register argument spill isn't the argument
+     passed on stack from caller.  */
+  switch (GET_CODE (pat))
     {
-      tree var = get_base_address (mem_expr);
-      return TREE_CODE (var) == PARM_DECL;
+    case SET:
+      return !ix86_spill_register_argument_p (pat, op, var);
+    case PARALLEL:
+      for (int i = 0; i < XVECLEN (pat, 0); i++)
+	{
+	  rtx exp = XVECEXP (pat, 0, i);
+	  if (GET_CODE (exp) == SET
+	      && ix86_spill_register_argument_p (exp, op, var))
+	    return false;
+	}
+      /* Fall through.  */
+    default:
+      break;
     }
-  return false;
+
+  return true;
 }
 
 /* Update the maximum stack slot alignment from memory alignment in PAT.  */
@@ -8642,7 +8691,7 @@ ix86_update_stack_alignment (rtx, const_rtx pat, void *data)
 	     responsible to align the outgoing stack for arguments
 	     passed on stack.  */
 	  if (reg_mentioned_p (p->reg, XEXP (op, 0))
-	      && !ix86_argument_passed_on_stack_p (op))
+	      && !ix86_argument_passed_on_stack_p (op, pat))
 	    {
 	      unsigned int alignment = MEM_ALIGN (op);
 
diff --git a/gcc/testsuite/gcc.target/i386/pr126320.c b/gcc/testsuite/gcc.target/i386/pr126320.c
new file mode 100644
index 00000000000..cad2205f3c9
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr126320.c
@@ -0,0 +1,45 @@
+/* { dg-do run } */
+/* { dg-options "-O1 -march=x86-64" } */
+
+#include <stdint.h>
+
+typedef int64_t v2i64 __attribute__ ((vector_size (16)));
+void *g4, *f3_p2;
+int8_t g15, g23;
+v2i64 g21;
+_Bool g22, f3_c4;
+__attribute__ ((__vector_size__ (16 * sizeof (int)))) int g26;
+int16_t g29;
+
+__attribute__((noipa, noinline, target("avx2")))
+void
+do_test (v2i64 a1)
+{
+  int16_t v3;
+lbl_entry:
+  f3_p2 = &a1;
+  v3 = g29;
+  if (g22)
+    goto lbl_bf4;
+  f3_c4 = v3 - 709;
+  if (f3_c4)
+    return;
+lbl_bf4:
+  g21 = a1;
+  uint8_t __ov_tmp_g15;
+  g15 = __ov_tmp_g15;
+  a1[0] = 0;
+  g26 = g26 == ~g26;
+  g4 = f3_p2;
+  g23 = 0;
+  goto lbl_entry;
+}
+
+int
+main (void)
+{
+ if (__builtin_cpu_supports ("avx2"))
+   do_test (g21);
+
+  return 0;
+}
-- 
2.55.0

Reply via email to