This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[patch] Vectorization of strided accesses - two fixes
- From: Ira Rosen <IRAR at il dot ibm dot com>
- To: gcc-patches at gnu dot org
- Date: Mon, 11 Dec 2006 14:59:06 +0200
- Subject: [patch] Vectorization of strided accesses - two fixes
This patch addresses two bugs in strided access vectorization support:
1. Consider the endianess when generating strided stores
(interleave_high/low statement creation). It was ignored before.
2. Fix strided stores with gaps detection. Without this patch there is
only a check for gaps between stores, and, therefore, the case of a gap
after contiguous stores was not treated.
Testcases are included.
Tested on powerpc-linux and x86-linux.
With this patch bootstrap with vectorization enabled passes on x86 (BTW,
bootstrap with vectorization enabled still fails on powerpc - PR28752 -
still looking into it on and off - tips are welcome...).
O.K. for mainline?
Thanks,
Ira
:ADDPATCH SSA (vectorizer):
ChangeLog entry:
* tree-vect-analyze.c (vect_analyze_data_ref_access): Add another
check for stores with gaps.
* tree-vect-transform.c (vect_permute_store_chain): Create
interleave_high or interleave_low
according to the endianess.
The patch:
Index: tree-vect-analyze.c
===================================================================
--- tree-vect-analyze.c (revision 119730)
+++ tree-vect-analyze.c (working copy)
@@ -1804,7 +1804,8 @@ vect_analyze_data_ref_access (struct dat
/* COUNT is the number of accesses found, we multiply it by the size
of
the type to get COUNT_IN_BYTES. */
count_in_bytes = type_size * count;
- /* Check the size of the interleaving is not greater than STEP. */
+
+ /* Check that the size of the interleaving is not greater than STEP.
*/
if (dr_step < count_in_bytes)
{
if (vect_print_dump_info (REPORT_DETAILS))
@@ -1815,6 +1816,15 @@ vect_analyze_data_ref_access (struct dat
return false;
}
+ /* Check that the size of the interleaving is equal to STEP for
stores,
+ i.e., that there are no gaps. */
+ if (!DR_IS_READ (dr) && dr_step != count_in_bytes)
+ {
+ if (vect_print_dump_info (REPORT_DETAILS))
+ fprintf (vect_dump, "interleaved store with gaps");
+ return false;
+ }
+
/* Check that STEP is a multiple of type size. */
if ((dr_step % type_size) != 0)
{
Index: tree-vect-transform.c
===================================================================
--- tree-vect-transform.c (revision 119730)
+++ tree-vect-transform.c (working copy)
@@ -2595,9 +2595,14 @@ vect_permute_store_chain (VEC(tree,heap)
/* high = interleave_high (vect1, vect2); */
perm_dest = create_tmp_var (vectype, "vect_inter_high");
add_referenced_var (perm_dest);
- perm_stmt = build2 (GIMPLE_MODIFY_STMT, void_type_node,
perm_dest,
- build2 (VEC_INTERLEAVE_HIGH_EXPR, vectype,
vect1,
- vect2));
+ if (BYTES_BIG_ENDIAN)
+ perm_stmt = build2 (GIMPLE_MODIFY_STMT, void_type_node,
perm_dest,
+ build2 (VEC_INTERLEAVE_HIGH_EXPR, vectype,
+ vect1, vect2));
+ else
+ perm_stmt = build2 (GIMPLE_MODIFY_STMT, void_type_node,
perm_dest,
+ build2 (VEC_INTERLEAVE_LOW_EXPR, vectype,
+ vect1, vect2));
high = make_ssa_name (perm_dest, perm_stmt);
GIMPLE_STMT_OPERAND (perm_stmt, 0) = high;
vect_finish_stmt_generation (stmt, perm_stmt, bsi);
@@ -2606,9 +2611,14 @@ vect_permute_store_chain (VEC(tree,heap)
/* low = interleave_low (vect1, vect2); */
perm_dest = create_tmp_var (vectype, "vect_inter_low");
add_referenced_var (perm_dest);
- perm_stmt = build2 (GIMPLE_MODIFY_STMT, void_type_node,
perm_dest,
- build2 (VEC_INTERLEAVE_LOW_EXPR, vectype,
vect1,
- vect2));
+ if (BYTES_BIG_ENDIAN)
+ perm_stmt = build2 (GIMPLE_MODIFY_STMT, void_type_node,
perm_dest,
+ build2 (VEC_INTERLEAVE_LOW_EXPR, vectype,
+ vect1, vect2));
+ else
+ perm_stmt = build2 (GIMPLE_MODIFY_STMT, void_type_node,
perm_dest,
+ build2 (VEC_INTERLEAVE_HIGH_EXPR, vectype,
+ vect1, vect2));
low = make_ssa_name (perm_dest, perm_stmt);
GIMPLE_STMT_OPERAND (perm_stmt, 0) = low;
vect_finish_stmt_generation (stmt, perm_stmt, bsi);
Index: testsuite/gcc.dg/vect/vect-strided-store-u32-i2.c
===================================================================
--- testsuite/gcc.dg/vect/vect-strided-store-u32-i2.c (revision 0)
+++ testsuite/gcc.dg/vect/vect-strided-store-u32-i2.c (revision 0)
@@ -0,0 +1,45 @@
+/* { dg-require-effective-target vect_float } */
+
+#include <stdarg.h>
+#include <stdio.h>
+#include "tree-vect.h"
+
+#define N 16
+
+int
+main1 (void)
+{
+ int i;
+ int a[N*2];
+ int b[N] = {0,2,4,6,8,10,12,14,16,18,20,22,24,26,28,30};
+ int c[N] = {1,3,5,7,9,11,13,15,17,19,21,23,25,27,29,31};
+
+ /* Strided access pattern. */
+ for (i = 0; i < N/2; i++)
+ {
+ a[i*2] = b[i] + c[i];
+ a[i*2+1] = b[i] * c[i];
+ }
+
+ /* Check results. */
+ for (i = 0; i < N/2; i++)
+ {
+ if (a[i*2] != b[i] + c[i]
+ || a[i*2+1] != b[i] * c[i])
+ abort();
+ }
+
+ return 0;
+}
+
+int main (void)
+{
+ check_vect ();
+ return main1 ();
+}
+
+/* Needs interleaving support. */
+/* { dg-final { scan-tree-dump-times "vectorized 1 loops" 1 "vect" {
target { vect_interleave } } } } */
+/* { dg-final { scan-tree-dump-times "vectorized 0 loops" 1 "vect" { xfail
{ vect_interleave } } } } */
+/* { dg-final { cleanup-tree-dump "vect" } } */
+
Index: testsuite/gcc.dg/vect/vect-strided-store-a-u8-i2.c
===================================================================
--- testsuite/gcc.dg/vect/vect-strided-store-a-u8-i2.c (revision 0)
+++ testsuite/gcc.dg/vect/vect-strided-store-a-u8-i2.c (revision 0)
@@ -0,0 +1,60 @@
+/* { dg-require-effective-target vect_int } */
+
+#include <stdarg.h>
+#include "tree-vect.h"
+
+#define N 64
+
+typedef struct {
+ unsigned char a;
+ unsigned char b;
+} s;
+
+int
+main1 ()
+{
+ s arr[N];
+ s *ptr = arr;
+ s res[N];
+ int i;
+ unsigned char a[N], b[N];
+
+
+ for (i = 0; i < N; i++)
+ {
+ a[i] = i;
+ b[i] = i * 2;
+ if (a[i] == 178)
+ abort();
+ }
+
+ for (i = 0; i < N; i++)
+ {
+ res[i].a = a[i] + 3;
+ res[i].b = a[i] + b[i];
+ ptr++;
+ }
+
+ /* check results: */
+ for (i = 0; i < N; i++)
+ {
+ if (res[i].a != a[i] + 3
+ || res[i].b != a[i] + b[i])
+ abort ();
+ }
+
+ return 0;
+}
+
+int main (void)
+{
+ check_vect ();
+
+ main1 ();
+
+ return 0;
+}
+
+/* { dg-final { scan-tree-dump-times "vectorized 1 loops" 1 "vect" {
target { vect_interleave } } } } */
+/* { dg-final { cleanup-tree-dump "vect" } } */
+
Index: testsuite/gcc.dg/vect/vect-strided-store-u16-i4.c
===================================================================
--- testsuite/gcc.dg/vect/vect-strided-store-u16-i4.c (revision 0)
+++ testsuite/gcc.dg/vect/vect-strided-store-u16-i4.c (revision 0)
@@ -0,0 +1,73 @@
+/* { dg-require-effective-target vect_int } */
+
+#include <stdarg.h>
+#include "tree-vect.h"
+
+#define N 128
+
+typedef struct {
+ unsigned short a;
+ unsigned short b;
+ unsigned short c;
+ unsigned short d;
+} s;
+
+unsigned short a[N];
+unsigned short b[N];
+unsigned short c[N];
+
+int
+main1 (s *arr)
+{
+ int i;
+ s *ptr = arr;
+ s res[N];
+ unsigned short x, y, z, w;
+
+ for (i = 0; i < N; i++)
+ {
+ res[i].c = a[i];
+ res[i].a = b[i];
+ res[i].d = c[i];
+ res[i].b = a[i] + b [i];
+ ptr++;
+ }
+
+ /* check results: */
+ for (i = 0; i < N; i++)
+ {
+ if (res[i].c != a[i]
+ || res[i].a != b[i]
+ || res[i].d != c[i]
+ || res[i].b != a[i] + b[i])
+ abort ();
+ }
+
+ return 0;
+}
+
+int main (void)
+{
+ int i;
+ s arr[N];
+
+ check_vect ();
+
+ for (i = 0; i < N; i++)
+ {
+ a[i] = i;
+ b[i] = i * 2;
+ c[i] = 17;
+ if (a[i] == 178)
+ abort();
+ }
+
+ main1 (arr);
+
+ return 0;
+}
+
+/* { dg-final { scan-tree-dump-times "vectorized 1 loops" 1 "vect" {
target { vect_interleave } } } } */
+/* { dg-final { cleanup-tree-dump "vect" } } */
+
+
Index: testsuite/gcc.dg/vect/vect-strided-u8-i8-gap4.c
===================================================================
--- testsuite/gcc.dg/vect/vect-strided-u8-i8-gap4.c (revision 119730)
+++ testsuite/gcc.dg/vect/vect-strided-u8-i8-gap4.c (working copy)
@@ -49,8 +49,26 @@ main1 (s *arr)
|| res[i].e != arr[i].b + arr[i].e
|| res[i].h != arr[i].c
|| res[i].g != arr[i].b + arr[i].c)
- abort();
+ abort ();
}
+
+ ptr = arr;
+ /* Not vectorizable: gap in store. */
+ for (i = 0; i < N; i++)
+ {
+ res[i].a = ptr->b;
+ res[i].b = ptr->c;
+ ptr++;
+ }
+
+ /* Check results. */
+ for (i = 0; i < N; i++)
+ {
+ if (res[i].a != arr[i].b
+ || res[i].b != arr[i].c)
+ abort ();
+ }
+
}