Cover the places where an object needs more alignment than the frame can
give it: the home slot of a by-value parameter, both when nothing else sees
it and when its address escapes to a callee, the hidden copy the caller makes
when the MS ABI passes an argument by reference, and a copy that GCC merely
prefers to over-align.

Where nothing else sees the object, it only has to be stored with a move that
matches its slot, so those tests scan for the move GCC selects.  Where the
address escapes, the object must really be aligned, so those tests scan for
the mask that rounds the slot address up.  None of them runs the code: a slot
that is short of the alignment the object needs still lands on a 32-byte
boundary about half the time.

The dg-do run C++ test covers an over-aligned temporary used on both arms of
a branch.

gcc/testsuite/ChangeLog:

        PR target/54412
        * g++.target/i386/pr54412-highpart-extract-rt.C: New test.
        * gcc.target/i386/pr54412-aligned-struct-byval-temp.c: New test.
        * gcc.target/i386/pr54412-blkmode-temp-biggest-align.c: New test.
        * gcc.target/i386/pr54412-escaping-param.c: New test.
        * gcc.target/i386/pr54412-m256-byval-param.c: New test.

Signed-off-by: Oleg Tolmatcev <[email protected]>
---
 .../i386/pr54412-highpart-extract-rt.C        | 110 ++++++++++++++++++
 .../i386/pr54412-aligned-struct-byval-temp.c  |  16 +++
 .../i386/pr54412-blkmode-temp-biggest-align.c |  16 +++
 .../gcc.target/i386/pr54412-escaping-param.c  |  20 ++++
 .../i386/pr54412-m256-byval-param.c           |  22 ++++
 5 files changed, 184 insertions(+)
 create mode 100644 gcc/testsuite/g++.target/i386/pr54412-highpart-extract-rt.C
 create mode 100644 
gcc/testsuite/gcc.target/i386/pr54412-aligned-struct-byval-temp.c
 create mode 100644 
gcc/testsuite/gcc.target/i386/pr54412-blkmode-temp-biggest-align.c
 create mode 100644 gcc/testsuite/gcc.target/i386/pr54412-escaping-param.c
 create mode 100644 gcc/testsuite/gcc.target/i386/pr54412-m256-byval-param.c

diff --git a/gcc/testsuite/g++.target/i386/pr54412-highpart-extract-rt.C 
b/gcc/testsuite/g++.target/i386/pr54412-highpart-extract-rt.C
new file mode 100644
index 0000000000..7c1d48c5d5
--- /dev/null
+++ b/gcc/testsuite/g++.target/i386/pr54412-highpart-extract-rt.C
@@ -0,0 +1,110 @@
+/* PR target/54412 */
+/* Check that "assign_stack_temp_for_type" safely reuses an over-aligned
+   temporary across control-flow paths.  The stack slot used by Vec4q (z0)
+   is reused for Vec4q (z1).  Its dynamically aligned address is computed in
+   the first branch and held in a pseudo-register that is undefined along the
+   second path, so the address must be recomputed when the slot is reused.  */
+/* { dg-do run { target { x86_64-*-mingw* && avx2 } } } */
+/* { dg-options "-O0 -mavx2 -std=gnu++17 -fno-omit-frame-pointer" } */
+/* { dg-require-effective-target avx2_runtime } */
+
+#include "avx2-check.h"
+
+typedef long long v4di __attribute__ ((vector_size (32), aligned (32)));
+
+static inline v4di
+make_v4di (long long a0, long long a1, long long a2, long long a3)
+{
+  return (v4di) { a0, a1, a2, a3 };
+}
+
+struct Vec256b
+{
+  v4di ymm;
+
+  Vec256b () = default;
+  explicit Vec256b (v4di x) : ymm (x) {}
+
+  __attribute__ ((noinline, noclone))
+  operator v4di () const
+  {
+    return ymm;
+  }
+};
+
+struct Vec4q : public Vec256b
+{
+  Vec4q () = default;
+
+  __attribute__ ((noinline, noclone))
+  explicit Vec4q (v4di x)
+  {
+    ymm = x;
+  }
+
+  __attribute__ ((noinline, noclone))
+  long long
+  extract (int index) const
+  {
+    long long elems[4] __attribute__ ((aligned (32)));
+    __builtin_memcpy (elems, &ymm, sizeof (elems));
+    return elems[index & 3];
+  }
+};
+
+struct Vec8q
+{
+  Vec256b z0;
+  Vec256b z1;
+
+  Vec8q () = default;
+  Vec8q (Vec256b a, Vec256b b) : z0 (a), z1 (b) {}
+
+  __attribute__ ((noinline, noclone))
+  long long
+  extract (int index) const
+  {
+    if ((unsigned) index < 4)
+      return Vec4q (z0).extract (index);
+
+    return Vec4q (z1).extract (index - 4);
+  }
+};
+
+__attribute__ ((noinline, noclone))
+static Vec8q
+passthru (Vec8q x)
+{
+  return x;
+}
+
+__attribute__ ((noinline, noclone))
+static long long
+call_extract (Vec8q x, int index)
+{
+  Vec8q y = passthru (x);
+
+  if ((unsigned) index >= 4)
+    {
+      register void *p __asm__ ("rbx") = (void *) 2;
+      asm volatile ("" : : "r" (p) : "memory");
+    }
+
+  return y.extract (index);
+}
+
+static void
+avx2_test ()
+{
+  Vec8q x (Vec256b (make_v4di (101, 102, 103, 104)),
+          Vec256b (make_v4di (201, 202, 203, 204)));
+
+  if (call_extract (x, 1) != 102)
+    __builtin_abort ();
+
+  if (call_extract (x, 5) != 202)
+    __builtin_abort ();
+
+  if (call_extract (x, 7) != 204)
+    __builtin_abort ();
+}
diff --git a/gcc/testsuite/gcc.target/i386/pr54412-aligned-struct-byval-temp.c 
b/gcc/testsuite/gcc.target/i386/pr54412-aligned-struct-byval-temp.c
new file mode 100644
index 0000000000..5f8a2409c6
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr54412-aligned-struct-byval-temp.c
@@ -0,0 +1,16 @@
+/* PR target/54412 */
+/* Check that "assign_stack_temp_for_type" preserves the required alignment
+   of a caller-created temporary for a by-reference argument.  */
+/* { dg-do compile { target x86_64-*-mingw* } } */
+/* { dg-options "-O2" } */
+/* { dg-final { scan-assembler {and[lq]?\t\$-32,} } } */
+
+struct S { char c[32]; } __attribute__((aligned (32)));
+
+void sink (struct S);
+
+void
+caller (struct S *p)
+{
+  sink (*p);
+}
diff --git a/gcc/testsuite/gcc.target/i386/pr54412-blkmode-temp-biggest-align.c 
b/gcc/testsuite/gcc.target/i386/pr54412-blkmode-temp-biggest-align.c
new file mode 100644
index 0000000000..72cbc1ee30
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr54412-blkmode-temp-biggest-align.c
@@ -0,0 +1,16 @@
+/* PR target/54412 */
+/* Check that "assign_stack_temp_for_type" does not overstate the alignment
+   of a "BLKmode" temporary.  */
+/* { dg-do compile { target x86_64-*-mingw* } } */
+/* { dg-options "-O2 -mavx" } */
+/* { dg-final { scan-assembler-not {vmov(aps|dqa)\t%ymm[0-9]+, 
[0-9-]*\(%r[sb]p\)} } } */
+
+struct S { char c[32]; };
+
+void sink (struct S);
+
+void
+caller (struct S *p)
+{
+  sink (*p);
+}
diff --git a/gcc/testsuite/gcc.target/i386/pr54412-escaping-param.c 
b/gcc/testsuite/gcc.target/i386/pr54412-escaping-param.c
new file mode 100644
index 0000000000..fb3c0bf534
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr54412-escaping-param.c
@@ -0,0 +1,20 @@
+/* PR target/54412 */
+/* Check that "assign_parm_setup_reg" correctly aligns the local copy of an
+   indirectly passed parameter whose address escapes.  */
+/* { dg-do compile { target x86_64-*-mingw* } } */
+/* { dg-options "-O2 -mavx" } */
+/* { dg-final { scan-assembler {and[lq]?\t\$-32,} } } */
+
+typedef float v8sf __attribute__ ((vector_size (32)));
+
+__attribute__ ((noipa)) v8sf
+get (const v8sf *p)
+{
+  return *p;
+}
+
+v8sf
+f (v8sf x)
+{
+  return get (&x);
+}
diff --git a/gcc/testsuite/gcc.target/i386/pr54412-m256-byval-param.c 
b/gcc/testsuite/gcc.target/i386/pr54412-m256-byval-param.c
new file mode 100644
index 0000000000..d2d1dcfcee
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr54412-m256-byval-param.c
@@ -0,0 +1,22 @@
+/* PR target/54412 */
+/* Check that "assign_parm_setup_reg" does not emit an aligned store to an
+   under-aligned local copy of an indirectly passed "__m256" parameter.
+
+   MSYS2/MINGW-packages#1209: X needs 32-byte alignment, but under SEH the
+   frame is only 16-byte aligned.  GCC put its home slot in a plain 16-byte
+   slot, still treated it as 32-byte aligned and stored X with vmovaps.
+   Nothing else sees X, so the move only has to match the slot.  Check the
+   move instead of running: the bad slot is 32-byte aligned about half the
+   time.  */
+/* { dg-do compile { target x86_64-*-mingw* } } */
+/* { dg-options "-O0 -mavx" } */
+/* { dg-final { scan-assembler-not {vmovaps\t%ymm0, -[0-9]+\(%rbp\)} } } */
+
+typedef float __m256 __attribute__ ((__vector_size__ (32),
+                                    __may_alias__));
+
+void
+foo (__m256 x)
+{
+  (void) x;
+}
-- 
2.55.0.windows.5

Reply via email to