Re: [PATCH v2] x86: Check DECL_INCOMING_RTL for argument passing check

"H.J. Lu" <[email protected]> Tue, 4 Aug 2026 15:02:23 +0800
Newsgroups gmane.comp.gcc.patches
Message-ID <CAMe9rOoWJf7eK8cdwzhdpm8W=2qVHOybaVTzVu7nCcygWbdOHA@mail.gmail.com>
On Tue, Aug 4, 2026 at 2:40 PM Hongtao Liu <[email protected]> wrote:
>
> On Sun, Aug 2, 2026 at 2:34 PM H.J. Lu <[email protected]> wrote:
> >
> > On Sat, Aug 1, 2026 at 4:49 PM Uros Bizjak <[email protected]> wrote:
> > >
> > > On Sat, Aug 1, 2026 at 5:12 AM H.J. Lu <[email protected]> wrote:
> > > >
> > > > When checking if a register argument is used as local variable, also
> > > > return true if non-local variable is the source of the argument-linked
> > > > memory store.
> > > >
> > > > gcc/
> > > >
> > > > PR target/126529
> > > > * config/i386/i386.cc (ix86_spill_register_argument_p): Also
> > > > check non-local variable source for the argument-linked memory
> > > > store.
> > > >
> > > > gcc/testsuite/
> > > >
> > > > PR target/126529
> > > > * gcc.target/i386/pr126529.c: New test.
> > >
> > > This is the third patch in the same area, so it IMO points to a more
> > > systematic issue. Please find someone else that is able to thoroughly
> > > review the patch (and the core issue that lies behind these problems)
> > > from the generic middle-end side of the compiler.
> > >
> > > Uros.
> >
> > Here is the v2 patch to check the argument's  DECL_INCOMING_RTL
> > instead.
>
>   /* Return true if OP is passed in memory.  */
>   return MEM_P (DECL_INCOMING_RTL (var));
>
> DECL_INCOMING_RTL mean param_decl in stack, callee can also take the
> parameter as local variable and put it in it's own stack, but looks
> like at assign_stack_local have already handled that case, and here in
> ix86_find_max_used_stack_alignment it just raise the requirement, not
> lower that. So it seems ok.
> Better to add more explanation in the comment.
> Also to be defensive, avoid NULL for DECL_INCOMING_RTL (var), change it to
>   return DECL_INCOMING_RTL (var) && MEM_P (DECL_INCOMING_RTL (var));
> ?

Here is the patch I am checking in.  I copied DECL_INCOMING_RTL comments
from tree.h:

static bool
ix86_argument_passed_on_stack_p (const_rtx op)
{
  tree mem_expr = MEM_EXPR (op);
  if (!mem_expr)
    return false;

  tree var = get_base_address (mem_expr);
  if (TREE_CODE (var) != PARM_DECL)
    return false;

  /* For PARM_DECL, DECL_INCOMING_RTL holds an RTL for the stack slot
     or register where the data was actually passed.  Return true if
     OP is passed in memory.  */
  return DECL_INCOMING_RTL (var) && MEM_P (DECL_INCOMING_RTL (var));
}

> Others LGTM.
>


-- 
H.J.
0001-x86-Check-DECL_INCOMING_RTL-for-argument-passing-che.patch (text/x-patch, 8.6 KB)
From 5a24a7bb515c918124259c999d9d2ceaa1742e1a Mon Sep 17 00:00:00 2001
From: "H.J. Lu" <[email protected]>
Date: Sat, 1 Aug 2026 06:07:43 +0800
Subject: [PATCH] x86: Check DECL_INCOMING_RTL for argument passing check

For argument declaration, its DECL_INCOMING_RTL holds an RTL for the
stack slot or register where the data was actually passed.  If an
argument's DECL_INCOMING_RTL is a memory operand, it is passed on stack
by caller.  Change ix86_argument_passed_on_stack_p to return true if the
argument's DECL_INCOMING_RTL is a memory operand.

gcc/

	PR target/126320
	PR target/126450
	PR target/126529
	* config/i386/i386.cc (ix86_spill_register_argument_p): Removed.
	(ix86_argument_passed_on_stack_p): Remove the second argument.
	Return true if the argument's DECL_INCOMING_RTL is a memory
	operand.
	(ix86_update_stack_alignment): Updated.

gcc/testsuite/

	PR target/126320
	PR target/126450
	PR target/126529
	* gcc.target/i386/pr126529-1.c: New test.
	* gcc.target/i386/pr126529-2.c: Likewise.
	* gcc.target/i386/pr126529-3.c: Likewise.
	* gcc.target/i386/pr126529-4.c: Likewise.

Signed-off-by: H.J. Lu <[email protected]>
---
 gcc/config/i386/i386.cc                    | 48 ++++------------------
 gcc/testsuite/gcc.target/i386/pr126529-1.c | 39 ++++++++++++++++++
 gcc/testsuite/gcc.target/i386/pr126529-2.c | 40 ++++++++++++++++++
 gcc/testsuite/gcc.target/i386/pr126529-3.c | 32 +++++++++++++++
 gcc/testsuite/gcc.target/i386/pr126529-4.c | 33 +++++++++++++++
 5 files changed, 151 insertions(+), 41 deletions(-)
 create mode 100644 gcc/testsuite/gcc.target/i386/pr126529-1.c
 create mode 100644 gcc/testsuite/gcc.target/i386/pr126529-2.c
 create mode 100644 gcc/testsuite/gcc.target/i386/pr126529-3.c
 create mode 100644 gcc/testsuite/gcc.target/i386/pr126529-4.c

diff --git a/gcc/config/i386/i386.cc b/gcc/config/i386/i386.cc
index 84dd3d18454..780651ebf8c 100644
--- a/gcc/config/i386/i386.cc
+++ b/gcc/config/i386/i386.cc
@@ -8609,42 +8609,10 @@ struct stack_access_data
   unsigned int *stack_alignment;
 };
 
-/* SET stores into OP, a MEM linked to parameter BASE.  Return true if
-   SET stores BASE's argument register into OP.  This is a spill: the
-   callee saves its own register argument to the stack.  It is not a
-   stack argument set up by the caller:
-
-     (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 ]))
- */
-
-static bool
-ix86_spill_register_argument_p (const_rtx set, const_rtx op, tree base)
-{
-  rtx src = SET_SRC (set);
-
-  /* Not a hard register store, so not a spill.  */
-  if (!REG_P (src) || !HARD_REGISTER_P (src))
-    return false;
-
-  rtx dest = SET_DEST (set);
-  tree reg_expr = REG_EXPR (src);
-
-  /* If spilling an SSA_NAME into OP, the argument-linked memory is
-     also used to store a local variable.  */
-  return dest == op && (reg_expr == base
-			|| (reg_expr
-			    && TREE_CODE (reg_expr) == SSA_NAME));
-}
-
-/* Return true if OP, found in PAT, is a stack argument set up by the
-   caller.  Return false if OP is a register argument that the callee
-   spilled to its own stack frame.  Both cases share the same MEM_EXPR,
-   so we must check PAT to tell them apart.  */
+/* Return true if OP is a stack argument set up by the caller.  */
 
 static bool
-ix86_argument_passed_on_stack_p (const_rtx op, const_rtx pat)
+ix86_argument_passed_on_stack_p (const_rtx op)
 {
   tree mem_expr = MEM_EXPR (op);
   if (!mem_expr)
@@ -8654,12 +8622,10 @@ ix86_argument_passed_on_stack_p (const_rtx op, const_rtx pat)
   if (TREE_CODE (var) != PARM_DECL)
     return false;
 
-  /* PAT is always a single SET here: note_stores splits PARALLEL
-     patterns into separate SETs before calling this function.  */
-  if (GET_CODE (pat) == SET)
-    return !ix86_spill_register_argument_p (pat, op, var);
-
-  return true;
+  /* For PARM_DECL, DECL_INCOMING_RTL holds an RTL for the stack slot
+     or register where the data was actually passed.  Return true if
+     OP is passed in memory.  */
+  return DECL_INCOMING_RTL (var) && MEM_P (DECL_INCOMING_RTL (var));
 }
 
 /* Update the maximum stack slot alignment from memory alignment in PAT.  */
@@ -8681,7 +8647,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, pat))
+	      && !ix86_argument_passed_on_stack_p (op))
 	    {
 	      unsigned int alignment = MEM_ALIGN (op);
 
diff --git a/gcc/testsuite/gcc.target/i386/pr126529-1.c b/gcc/testsuite/gcc.target/i386/pr126529-1.c
new file mode 100644
index 00000000000..aa53283e5e3
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr126529-1.c
@@ -0,0 +1,39 @@
+/* { dg-do run } */
+/* { dg-options "-O2 -march=x86-64" } */
+
+typedef signed char A[[gnu::vector_size (2)]];
+typedef short B[[gnu::vector_size (16)]];
+int a, b, c, d;
+B e;
+[[gnu::vector_size(8 * sizeof (int))]] int f;
+_Bool g;
+
+__attribute__((noipa, noinline, target("avx2")))
+void *
+foo (long long x, _Bool y, int z, B w)
+{
+  A h = {};
+  short i = h[z];
+  f = 0 % f;
+  w = e;
+  d = w[g];
+  h = ((union { short s; A t; }) { i }).t;
+  b = 3 / x;
+  h = __builtin_shufflevector (h, h, 3, 2);
+lab:
+  c = h[0];
+  if (y)
+    return 0;
+  y = 1;
+  h = ~h;
+  goto lab;
+}
+
+int
+main (void)
+{
+ if (__builtin_cpu_supports ("avx2"))
+   foo (3355934481768670720LL, 0, a, e);
+
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.target/i386/pr126529-2.c b/gcc/testsuite/gcc.target/i386/pr126529-2.c
new file mode 100644
index 00000000000..d37c0bf5997
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr126529-2.c
@@ -0,0 +1,40 @@
+/* { dg-do run } */
+/* { dg-options "-O2 -march=x86-64" } */
+
+typedef signed char A[[gnu::vector_size (2)]];
+typedef short B[[gnu::vector_size (16)]];
+int a, b, c, d;
+B e;
+[[gnu::vector_size(8 * sizeof (int))]] int f;
+_Bool g;
+
+__attribute__((noipa, noinline, target("avx2")))
+void *
+foo (float f1, float f2, float f3, float f4, float f5, float f6, float f7,
+     float f8, long long x, _Bool y, int z, B w)
+{
+  A h = {};
+  short i = h[z];
+  f = 0 % f;
+  w = e;
+  d = w[g];
+  h = ((union { short s; A t; }) { i }).t;
+  b = 3 / x;
+  h = __builtin_shufflevector (h, h, 3, 2);
+lab:
+  c = h[0];
+  if (y)
+    return 0;
+  y = 1;
+  h = ~h;
+  goto lab;
+}
+
+int
+main (void)
+{
+ if (__builtin_cpu_supports ("avx2"))
+   foo (1, 2, 3, 4, 5, 6, 7, 8, 3355934481768670720LL, 0, a, e);
+
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.target/i386/pr126529-3.c b/gcc/testsuite/gcc.target/i386/pr126529-3.c
new file mode 100644
index 00000000000..740b21b1b28
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr126529-3.c
@@ -0,0 +1,32 @@
+/* { dg-do compile { target *-*-linux* } } */
+/* { dg-options "-O2 -march=x86-64-v3" } */
+/* { dg-final { scan-assembler "and\[lq\]?\[\\t \]+\\$-32,\[\\t \]*%\[re\]?sp" } } */
+/* { dg-final { scan-assembler "vmovdqa\[\\t \]+%ymm" } } */
+
+typedef signed char A[[gnu::vector_size (2)]];
+typedef short B[[gnu::vector_size (32)]];
+int a, b, c, d;
+B e;
+[[gnu::vector_size(8 * sizeof (int))]] int f;
+_Bool g;
+
+[[gnu::noipa]] void *
+foo (float f1, float f2, float f3, float f4, float f5, float f6, float f7,
+     long long x, _Bool y, int z, B w)
+{
+  A h = {};
+  short i = h[z];
+  f = 0 % f;
+  w = e;
+  d = w[g];
+  h = ((union { short s; A t; }) { i }).t;
+  b = 3 / x;
+  h = __builtin_shufflevector (h, h, 3, 2);
+lab:
+  c = h[0];
+  if (y)
+    return 0;
+  y = 1;
+  h = ~h;
+  goto lab;
+}
diff --git a/gcc/testsuite/gcc.target/i386/pr126529-4.c b/gcc/testsuite/gcc.target/i386/pr126529-4.c
new file mode 100644
index 00000000000..2c08d56ca23
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr126529-4.c
@@ -0,0 +1,33 @@
+/* { dg-do compile { target *-*-linux* } } */
+/* { dg-options "-O2 -march=x86-64-v3" } */
+/* { dg-final { scan-assembler "and\[lq\]?\[\\t \]+\\$-32,\[\\t \]*%\[re\]?sp" { target ia32 } } } */
+/* { dg-final { scan-assembler-not "and\[lq\]?\[\\t \]+\\$-32,\[\\t \]*%\[re\]?sp" { target { ! ia32 } } } } */
+/* { dg-final { scan-assembler "vmovdqa\[\\t \]+%ymm" } } */
+
+typedef signed char A[[gnu::vector_size (2)]];
+typedef short B[[gnu::vector_size (32)]];
+int a, b, c, d;
+B e;
+[[gnu::vector_size(8 * sizeof (int))]] int f;
+_Bool g;
+
+[[gnu::noipa]] void *
+foo (float f1, float f2, float f3, float f4, float f5, float f6, float f7,
+     float f8, long long x, _Bool y, int z, B w)
+{
+  A h = {};
+  short i = h[z];
+  f = 0 % f;
+  w = e;
+  d = w[g];
+  h = ((union { short s; A t; }) { i }).t;
+  b = 3 / x;
+  h = __builtin_shufflevector (h, h, 3, 2);
+lab:
+  c = h[0];
+  if (y)
+    return 0;
+  y = 1;
+  h = ~h;
+  goto lab;
+}
-- 
2.55.0