When the size of record or array is smaller than the target alignment,
don't over align them and set DR_TARGET_ALIGNMENT to the reduced target
alignment.  If the natural alignment isn't lower than the reduced target
alignment, set base_misaligned to false.

gcc/

PR middle-end/126410
* tree-vect-data-refs.cc (vect_compute_data_ref_alignment): Don't
over align record and array.
* tree-vect-stmts.cc (vectorizable_store): No unaligned access
dump if DR_TARGET_ALIGNMENT is less than the vector alignment.
(vectorizable_load): Likewise.

gcc/testsuite/

PR middle-end/126410
* gcc.target/i386/pr126410-1a.c: New test.
* gcc.target/i386/pr126410-1b.c: Likewise.
* gcc.target/i386/pr126410-1c.c: Likewise.
* gcc.target/i386/pr126410-2a.c: Likewise.
* gcc.target/i386/pr126410-2b.c: Likewise.
* gcc.target/i386/pr126410-2c.c: Likewise.


-- 
H.J.
From 2c6b545a7181ba6a6dfebb7c188b55f6dc57910a Mon Sep 17 00:00:00 2001
From: "H.J. Lu" <[email protected]>
Date: Sun, 26 Jul 2026 19:21:55 +0800
Subject: [PATCH] vectorizer: Don't over align record and array

When the size of record or array is smaller than the target alignment,
don't over align them and set DR_TARGET_ALIGNMENT to the reduced target
alignment.  If the natural alignment isn't lower than the reduced target
alignment, set base_misaligned to false.

gcc/

	PR middle-end/126410
	* tree-vect-data-refs.cc (vect_compute_data_ref_alignment): Don't
	over align record and array.
	* tree-vect-stmts.cc (vectorizable_store): No unaligned access
	dump if DR_TARGET_ALIGNMENT is less than the vector alignment.
	(vectorizable_load): Likewise.

gcc/testsuite/

	PR middle-end/126410
	* gcc.target/i386/pr126410-1a.c: New test.
	* gcc.target/i386/pr126410-1b.c: Likewise.
	* gcc.target/i386/pr126410-1c.c: Likewise.
	* gcc.target/i386/pr126410-2a.c: Likewise.
	* gcc.target/i386/pr126410-2b.c: Likewise.
	* gcc.target/i386/pr126410-2c.c: Likewise.

Signed-off-by: H.J. Lu <[email protected]>
---
 gcc/testsuite/gcc.target/i386/pr126410-1a.c | 22 +++++++
 gcc/testsuite/gcc.target/i386/pr126410-1b.c |  8 +++
 gcc/testsuite/gcc.target/i386/pr126410-1c.c |  7 ++
 gcc/testsuite/gcc.target/i386/pr126410-2a.c | 22 +++++++
 gcc/testsuite/gcc.target/i386/pr126410-2b.c |  8 +++
 gcc/testsuite/gcc.target/i386/pr126410-2c.c |  7 ++
 gcc/tree-vect-data-refs.cc                  | 73 +++++++++++++++++----
 gcc/tree-vect-stmts.cc                      | 23 +++++--
 8 files changed, 152 insertions(+), 18 deletions(-)
 create mode 100644 gcc/testsuite/gcc.target/i386/pr126410-1a.c
 create mode 100644 gcc/testsuite/gcc.target/i386/pr126410-1b.c
 create mode 100644 gcc/testsuite/gcc.target/i386/pr126410-1c.c
 create mode 100644 gcc/testsuite/gcc.target/i386/pr126410-2a.c
 create mode 100644 gcc/testsuite/gcc.target/i386/pr126410-2b.c
 create mode 100644 gcc/testsuite/gcc.target/i386/pr126410-2c.c

diff --git a/gcc/testsuite/gcc.target/i386/pr126410-1a.c b/gcc/testsuite/gcc.target/i386/pr126410-1a.c
new file mode 100644
index 00000000000..489064cda6b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr126410-1a.c
@@ -0,0 +1,22 @@
+/* { dg-do compile { target *-*-linux* } } */
+/* { dg-options "-O2 -march=x86-64-v4 -fomit-frame-pointer" } */
+/* { dg-final { scan-assembler-not "and\[lq\]?\[\\t \]*\\$-64,\[\\t \]*%\[re\]?sp" } } */
+
+#ifndef N
+#define N 4
+#endif
+
+typedef float vector[N];
+
+extern vector v;
+
+extern void foo (vector *);
+
+void
+func (vector a, vector b)
+{
+  vector r;
+  for (int i = 0; i < N; i++)
+    r[i] = a[i] * b[i];
+  foo (&r);
+}
diff --git a/gcc/testsuite/gcc.target/i386/pr126410-1b.c b/gcc/testsuite/gcc.target/i386/pr126410-1b.c
new file mode 100644
index 00000000000..7e7141eb2e0
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr126410-1b.c
@@ -0,0 +1,8 @@
+/* { dg-do compile { target *-*-linux* } } */
+/* { dg-options "-O2 -march=x86-64-v4 -fomit-frame-pointer" } */
+/* { dg-final { scan-assembler "and\[lq\]?\[\\t \]*\\$-32,\[\\t \]*%\[re\]?sp" } } */
+/* { dg-final { scan-assembler-not "and\[lq\]?\[\\t \]*\\$-64,\[\\t \]*%\[re\]?sp" } } */
+
+#define N 8
+
+#include "pr126410-1a.c"
diff --git a/gcc/testsuite/gcc.target/i386/pr126410-1c.c b/gcc/testsuite/gcc.target/i386/pr126410-1c.c
new file mode 100644
index 00000000000..8b5fb5bc150
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr126410-1c.c
@@ -0,0 +1,7 @@
+/* { dg-do compile { target *-*-linux* } } */
+/* { dg-options "-O2 -march=x86-64-v4 -fomit-frame-pointer" } */
+/* { dg-final { scan-assembler "and\[lq\]?\[\\t \]*\\$-64,\[\\t \]*%\[re\]?sp" } } */
+
+#define N 16
+
+#include "pr126410-1a.c"
diff --git a/gcc/testsuite/gcc.target/i386/pr126410-2a.c b/gcc/testsuite/gcc.target/i386/pr126410-2a.c
new file mode 100644
index 00000000000..8bd45573145
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr126410-2a.c
@@ -0,0 +1,22 @@
+/* { dg-do compile { target *-*-linux* } } */
+/* { dg-options "-O2 -march=x86-64-v4 -fomit-frame-pointer" } */
+/* { dg-final { scan-assembler-not "and\[lq\]?\[\\t \]*\\$-64,\[\\t \]*%\[re\]?sp" } } */
+
+#ifndef N
+#define N 4
+#endif
+
+typedef struct { float values[N]; } vector;
+
+extern vector v;
+
+extern void foo (vector *);
+
+void
+func (vector a, vector b)
+{
+  vector r;
+  for (int i = 0; i < N; i++)
+    r.values[i] = a.values[i] * b.values[i];
+  foo (&r);
+}
diff --git a/gcc/testsuite/gcc.target/i386/pr126410-2b.c b/gcc/testsuite/gcc.target/i386/pr126410-2b.c
new file mode 100644
index 00000000000..30743cd73f1
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr126410-2b.c
@@ -0,0 +1,8 @@
+/* { dg-do compile { target *-*-linux* } } */
+/* { dg-options "-O2 -march=x86-64-v4 -fomit-frame-pointer" } */
+/* { dg-final { scan-assembler "and\[lq\]?\[\\t \]*\\$-32,\[\\t \]*%\[re\]?sp" } } */
+/* { dg-final { scan-assembler-not "and\[lq\]?\[\\t \]*\\$-64,\[\\t \]*%\[re\]?sp" } } */
+
+#define N 8
+
+#include "pr126410-2a.c"
diff --git a/gcc/testsuite/gcc.target/i386/pr126410-2c.c b/gcc/testsuite/gcc.target/i386/pr126410-2c.c
new file mode 100644
index 00000000000..d618b36e15b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr126410-2c.c
@@ -0,0 +1,7 @@
+/* { dg-do compile { target *-*-linux* } } */
+/* { dg-options "-O2 -march=x86-64-v4 -fomit-frame-pointer" } */
+/* { dg-final { scan-assembler "and\[lq\]?\[\\t \]*\\$-64,\[\\t \]*%\[re\]?sp" } } */
+
+#define N 16
+
+#include "pr126410-2a.c"
diff --git a/gcc/tree-vect-data-refs.cc b/gcc/tree-vect-data-refs.cc
index 0e0754769ae..64080098b64 100644
--- a/gcc/tree-vect-data-refs.cc
+++ b/gcc/tree-vect-data-refs.cc
@@ -1646,26 +1646,71 @@ vect_compute_data_ref_alignment (vec_info *vinfo, dr_vec_info *dr_info,
     {
       unsigned int max_alignment;
       tree base = get_base_for_alignment (drb->base_address, &max_alignment);
-      if (max_alignment < vect_align_c
-	  || (loop_vinfo && LOOP_VINFO_EPILOGUE_P (loop_vinfo))
-	  || !vect_can_force_dr_alignment_p (base,
-					     vect_align_c * BITS_PER_UNIT))
+      bool base_misaligned = true;
+
+      tree type = TREE_TYPE (base);
+      if (AGGREGATE_TYPE_P (type))
+	{
+	  poly_uint64 type_size;
+	  if (poly_int_tree_p (TYPE_SIZE_UNIT (type), &type_size)
+	      && type_size.is_constant ())
+	    {
+	      unsigned HOST_WIDE_INT size = type_size.to_constant ();
+	      if (size && size < vect_align_c)
+		{
+		  /* Don't over align record and array if data size is
+		     smaller than the target alignment.  */
+
+		  do
+		    {
+		      vect_align_c /= 2;
+		    }
+		  while (size < vect_align_c);
+
+		  if (base_alignment >= vect_align_c)
+		    {
+		      /* Set base_misaligned to false if the natural
+			 alignment is higher than the reduced target
+			 alignment.  */
+		      base_misaligned = false;
+		      if (dump_enabled_p ())
+			dump_printf_loc
+			  (MSG_NOTE, vect_location,
+			   "no need to force alignment of ref: %T\n",
+			   ref);
+		    }
+
+		  /* Set DR_TARGET_ALIGNMENT to the reduced target
+		     alignment.  */
+		  SET_DR_TARGET_ALIGNMENT (dr_info, vect_align_c);
+		}
+	    }
+	}
+
+      if (base_misaligned)
 	{
+	  if (max_alignment < vect_align_c
+	      || (loop_vinfo && LOOP_VINFO_EPILOGUE_P (loop_vinfo))
+	      || !vect_can_force_dr_alignment_p
+		    (base, vect_align_c * BITS_PER_UNIT))
+	    {
+	      if (dump_enabled_p ())
+		dump_printf_loc (MSG_NOTE, vect_location,
+				 "can't force alignment of ref: %T\n",
+				 ref);
+	      return;
+	    }
+
+	  /* Force the alignment of the decl.
+	     NOTE: This is the only change to the code we make during
+	     the analysis phase, before deciding to vectorize the loop.  */
 	  if (dump_enabled_p ())
 	    dump_printf_loc (MSG_NOTE, vect_location,
-			     "can't force alignment of ref: %T\n", ref);
-	  return;
+			     "force alignment of %T\n", ref);
 	}
 
-      /* Force the alignment of the decl.
-	 NOTE: This is the only change to the code we make during
-	 the analysis phase, before deciding to vectorize the loop.  */
-      if (dump_enabled_p ())
-	dump_printf_loc (MSG_NOTE, vect_location,
-			 "force alignment of %T\n", ref);
-
       dr_info->base_decl = base;
-      dr_info->base_misaligned = true;
+      dr_info->base_misaligned = base_misaligned;
       base_misalignment = 0;
     }
   poly_int64 misalignment
diff --git a/gcc/tree-vect-stmts.cc b/gcc/tree-vect-stmts.cc
index 488b9754bed..54d24c75663 100644
--- a/gcc/tree-vect-stmts.cc
+++ b/gcc/tree-vect-stmts.cc
@@ -8298,8 +8298,15 @@ vectorizable_store (vec_info *vinfo,
 	  && memory_access_type != VMAT_STRIDED_SLP
 	  && memory_access_type != VMAT_INVARIANT
 	  && alignment_support_scheme != dr_aligned)
-	dump_printf_loc (MSG_NOTE, vect_location,
-			 "Vectorizing an unaligned access.\n");
+	{
+	  /* DR_TARGET_ALIGNMENT may be reduced if data size is smaller
+	     than the vector alignment.  */
+	  unsigned int align = TYPE_ALIGN_UNIT (vectype);
+	  poly_uint64 target_align = DR_TARGET_ALIGNMENT (dr_info);
+	  if (known_ge (target_align, align))
+	    dump_printf_loc (MSG_NOTE, vect_location,
+			     "Vectorizing an unaligned access.\n");
+	}
     }
 
   /* Transform.  */
@@ -9967,8 +9974,16 @@ vectorizable_load (vec_info *vinfo,
 	  && memory_access_type != VMAT_STRIDED_SLP
 	  && memory_access_type != VMAT_INVARIANT
 	  && alignment_support_scheme != dr_aligned)
-	dump_printf_loc (MSG_NOTE, vect_location,
-			 "Vectorizing an unaligned access.\n");
+	{
+	  /* DR_TARGET_ALIGNMENT may be reduced if data size is smaller
+	     than the vector alignment.  */
+	  dr_vec_info *dr_info = STMT_VINFO_DR_INFO (stmt_info);
+	  unsigned int align = TYPE_ALIGN_UNIT (vectype);
+	  poly_uint64 target_align = DR_TARGET_ALIGNMENT (dr_info);
+	  if (known_ge (target_align, align))
+	    dump_printf_loc (MSG_NOTE, vect_location,
+			     "Vectorizing an unaligned access.\n");
+	}
 
       if (memory_access_type == VMAT_LOAD_STORE_LANES)
 	vinfo->any_known_not_updated_vssa = true;
-- 
2.55.0

Reply via email to