https://gcc.gnu.org/g:fa7bbb065c63aa802e0bbb04d605407dad58cf94

commit r15-3537-gfa7bbb065c63aa802e0bbb04d605407dad58cf94
Author: H.J. Lu <hjl.to...@gmail.com>
Date:   Fri Sep 6 05:24:07 2024 -0700

    x86-64: Don't use temp for argument in a TImode register
    
    Don't use temp for a PARALLEL BLKmode argument of an EXPR_LIST expression
    in a TImode register.  Otherwise, the TImode variable will be put in
    the GPR save area which guarantees only 8-byte alignment.
    
    gcc/
    
            PR target/116621
            * config/i386/i386.cc (ix86_gimplify_va_arg): Don't use temp for
            a PARALLEL BLKmode container of an EXPR_LIST expression in a
            TImode register.
    
    gcc/testsuite/
    
            PR target/116621
            * gcc.target/i386/pr116621.c: New test.
    
    Signed-off-by: H.J. Lu <hjl.to...@gmail.com>

Diff:
---
 gcc/config/i386/i386.cc                  | 22 ++++++++++++++--
 gcc/testsuite/gcc.target/i386/pr116621.c | 43 ++++++++++++++++++++++++++++++++
 2 files changed, 63 insertions(+), 2 deletions(-)

diff --git a/gcc/config/i386/i386.cc b/gcc/config/i386/i386.cc
index 707b75a6d5db..45320124b91c 100644
--- a/gcc/config/i386/i386.cc
+++ b/gcc/config/i386/i386.cc
@@ -4908,13 +4908,31 @@ ix86_gimplify_va_arg (tree valist, tree type, 
gimple_seq *pre_p,
 
       examine_argument (nat_mode, type, 0, &needed_intregs, &needed_sseregs);
 
-      need_temp = (!REG_P (container)
+      bool container_in_reg = false;
+      if (REG_P (container))
+       container_in_reg = true;
+      else if (GET_CODE (container) == PARALLEL
+              && GET_MODE (container) == BLKmode
+              && XVECLEN (container, 0) == 1)
+       {
+         /* Check if it is a PARALLEL BLKmode container of an EXPR_LIST
+            expression in a TImode register.  In this case, temp isn't
+            needed.  Otherwise, the TImode variable will be put in the
+            GPR save area which guarantees only 8-byte alignment.   */
+         rtx x = XVECEXP (container, 0, 0);
+         if (GET_CODE (x) == EXPR_LIST
+             && REG_P (XEXP (x, 0))
+             && XEXP (x, 1) == const0_rtx)
+           container_in_reg = true;
+       }
+
+      need_temp = (!container_in_reg
                   && ((needed_intregs && TYPE_ALIGN (type) > 64)
                       || TYPE_ALIGN (type) > 128));
 
       /* In case we are passing structure, verify that it is consecutive block
          on the register save area.  If not we need to do moves.  */
-      if (!need_temp && !REG_P (container))
+      if (!need_temp && !container_in_reg)
        {
          /* Verify that all registers are strictly consecutive  */
          if (SSE_REGNO_P (REGNO (XEXP (XVECEXP (container, 0, 0), 0))))
diff --git a/gcc/testsuite/gcc.target/i386/pr116621.c 
b/gcc/testsuite/gcc.target/i386/pr116621.c
new file mode 100644
index 000000000000..704266458a85
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr116621.c
@@ -0,0 +1,43 @@
+/* { dg-do run } */
+/* { dg-options "-O2" } */
+
+#include <stdarg.h>
+#include <string.h>
+
+union S8302
+{
+  union
+  {
+    double b;
+    int c;
+  } a;
+  long double d;
+  unsigned short int f[5];
+};
+
+union S8302 s8302;
+extern void check8302va (int i, ...);
+
+int
+main (void)
+{
+  memset (&s8302, '\0', sizeof (s8302));
+  s8302.a.b = -221438.250000;
+  check8302va (1, s8302);
+  return 0;
+}
+
+__attribute__((noinline, noclone))
+void
+check8302va (int z, ...)
+{
+  union S8302 arg, *p;
+  va_list ap;
+
+  __builtin_va_start (ap, z);
+  p = &s8302;
+  arg = __builtin_va_arg (ap, union S8302);
+  if (p->a.b != arg.a.b)
+    __builtin_abort ();
+  __builtin_va_end (ap);
+}

Reply via email to