aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIra Rosen <irar@il.ibm.com>2005-07-25 12:05:07 +0000
committerIra Rosen <irar@gcc.gnu.org>2005-07-25 12:05:07 +0000
commit86a0740499715b497e753af5b73c33ccb934c70b (patch)
tree2c7091212ab12d18c54b6a9e333f0b9450742dab
parent4fdfb2046e90d49c41efee579b8b7c76adebd26e (diff)
downloadgcc-86a0740499715b497e753af5b73c33ccb934c70b.zip
gcc-86a0740499715b497e753af5b73c33ccb934c70b.tar.gz
gcc-86a0740499715b497e753af5b73c33ccb934c70b.tar.bz2
expr.c (highest_pow2_factor): Make extern.
* expr.c (highest_pow2_factor): Make extern. * tree-data-ref.c (ptr_decl_may_alias_p): New function. (ptr_ptr_may_alias_p, may_alias_p, record_ptr_differ_p, record_array_differ_p, array_ptr_differ_p): Likewise. (base_object_differ_p): Rename (from array_base_name_differ_p). Support additional cases. Call the above functions. (base_addr_differ_p): Moved from tree-vect-analyze.c. Call base_object_differ_p when there are two base objects. Otherwise, compare base address and offset. Call may_alias_p. (dump_data_reference): Use a correct field name. (analyze_array): Make static. Initialize new data-ref fields. (analyze_indirect_ref): New function. (init_data_ref): Initialize new data-ref fields. (strip_conversion): Moved from tree-vect-analyze.c. (analyze_offset_expr, get_ptr_offset, address_analysis, object_analysis): Likewise. (analyze_offset): New function. (create_data_ref): Likewise. (initialize_data_dependence_relation): Call base_addr_differ_p. Compare dimensions for ARRAY_REFs only. (build_classic_dist_vector): Make static. (access_functions_are_affine_or_constant_p): Call macro to get the address of access functions. (compute_all_dependences): Add new parameter compute_self_and_read_read_dependences. Compute self and read-read dependences if it is true. (find_data_references_in_loop): Call create_data_ref. Initialize new data-ref fields. (compute_data_dependences_for_loop): Add new parameter compute_self_and_read_read_dependences. Remove parameter nb_loops, compute nb_loops. Call compute_all_dependences, build_classic_dist_vector and build_classic_dir_vector with correct parameters. (analyze_all_data_dependences): Call compute_data_dependences_for_loop with correct parameters. Compare dimensions for ARRAY_REFs only. (free_data_refs): Call macro to free access functions. * tree-data-ref.h (struct first_location_in_loop): New structure. Move fields from stmt_vinfo. (struct base_object_info): New structure. (struct data_reference): Move fields to base_object_info. Add fields first_location and object_info for above structures. Move fields from stmt_info: memtag, ptr_info, subvars, misalignment. Add new field aligned_to. Add macros to access the new fields. Update functions declarations. * tree-flow.h (is_aliased_with): Declare. * tree-loop-linear.c (linear_transform_loops): Call compute_data_dependences_for_loop with correct parameters. * tree-ssa-alias.c (is_aliased_with): New function. * tree-vect-analyze.c (vect_get_ptr_offset): Remove. (vect_analyze_offset_expr, vect_base_addr_differ_p): Likewise. (vect_analyze_data_ref_dependence): Get ddr. Remove call to vect_base_addr_differ_p, compute_subscript_distance and build_classic_dist_vector. Add printings. Check absolute value of distance. (vect_analyze_data_ref_dependences): Go through ddrs instead of data-refs. (vect_compute_data_ref_alignment): Get the fields of data-ref instead of stmt. Check aligned_to. Check if the base is aligned. Remove conversion to bytes. Add printing. (vect_compute_data_refs_alignment): Go through loads and stores in one loop. (vect_enhance_data_refs_alignment, vect_analyze_data_refs_alignment, vect_analyze_data_ref_access): Likewise. (vect_analyze_pointer_ref_access): Remove. (vect_address_analysis, vect_object_analysis): Likewise. (vect_analyze_data_refs): Call compute_data_dependences_for_loop to find and analyze data-refs in the loop. * tree-vect-transform.c (vect_create_addr_base_for_vector_ref): Get the fields of data-ref instead of stmt. Add init to the offset from the base. (vect_create_data_ref_ptr): Get the fields of data-ref instead of stmt. (vect_update_init_of_dr): Likewise. (vect_update_inits_of_drs): Go through loads and stores in one loop. * tree-vectorizer.c (new_stmt_vec_info): Remove initialization of removed fields. (new_loop_vec_info): Initialize new fields. (destroy_loop_vec_info): Free new fields. (vect_strip_conversion): Remove. * tree-vectorizer.h (enum verbosity_levels): Add new verbosity level. (struct _loop_vec_info): Unify data_ref_writes and data_ref_reads into datarefs. Add new field ddrs. Add macros for the new fields access. (struct _stmt_vec_info): Remove: base_address, initial_offset, step, base_aligned_p, misalignment, memtag, ptr_info and subvars. Remove their macros. * tree.h (highest_pow2_factor): Declare. From-SVN: r102356
-rw-r--r--gcc/ChangeLog85
-rw-r--r--gcc/expr.c3
-rw-r--r--gcc/testsuite/ChangeLog16
-rw-r--r--gcc/testsuite/g++.dg/vect/pr21218.cc18
-rw-r--r--gcc/testsuite/g++.dg/vect/vect.exp2
-rw-r--r--gcc/testsuite/gcc.dg/tree-ssa/ltrans-8.c13
-rw-r--r--gcc/testsuite/gcc.dg/vect/pr20122.c20
-rw-r--r--gcc/testsuite/gcc.dg/vect/vect-100.c80
-rw-r--r--gcc/testsuite/gcc.dg/vect/vect-101.c49
-rw-r--r--gcc/testsuite/gcc.dg/vect/vect-102.c55
-rw-r--r--gcc/testsuite/gcc.dg/vect/vect-103.c57
-rw-r--r--gcc/testsuite/gcc.dg/vect/vect-104.c66
-rw-r--r--gcc/testsuite/gcc.dg/vect/vect-105.c66
-rw-r--r--gcc/testsuite/gcc.dg/vect/vect-115.c75
-rw-r--r--gcc/testsuite/gcc.dg/vect/vect-116.c28
-rw-r--r--gcc/testsuite/gcc.dg/vect/vect-43.c26
-rw-r--r--gcc/testsuite/gcc.dg/vect/vect-91.c14
-rw-r--r--gcc/testsuite/gcc.dg/vect/vect.exp2
-rw-r--r--gcc/testsuite/gfortran.dg/vect/pr19049.f9024
-rw-r--r--gcc/testsuite/gfortran.dg/vect/vect-4.f9010
-rw-r--r--gcc/testsuite/gfortran.dg/vect/vect.exp2
-rw-r--r--gcc/tree-data-ref.c1477
-rw-r--r--gcc/tree-data-ref.h124
-rw-r--r--gcc/tree-flow.h1
-rw-r--r--gcc/tree-loop-linear.c2
-rw-r--r--gcc/tree-ssa-alias.c34
-rw-r--r--gcc/tree-vect-analyze.c1259
-rw-r--r--gcc/tree-vect-transform.c51
-rw-r--r--gcc/tree-vectorizer.c44
-rw-r--r--gcc/tree-vectorizer.h82
-rw-r--r--gcc/tree.h3
31 files changed, 2446 insertions, 1342 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 3963141..68be3ab 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,88 @@
+2005-07-25 Ira Rosen <irar@il.ibm.com>
+
+ * expr.c (highest_pow2_factor): Make extern.
+ * tree-data-ref.c (ptr_decl_may_alias_p): New function.
+ (ptr_ptr_may_alias_p, may_alias_p, record_ptr_differ_p,
+ record_array_differ_p, array_ptr_differ_p): Likewise.
+ (base_object_differ_p): Rename (from array_base_name_differ_p). Support
+ additional cases. Call the above functions.
+ (base_addr_differ_p): Moved from tree-vect-analyze.c. Call
+ base_object_differ_p when there are two base objects. Otherwise, compare
+ base address and offset. Call may_alias_p.
+ (dump_data_reference): Use a correct field name.
+ (analyze_array): Make static. Initialize new data-ref fields.
+ (analyze_indirect_ref): New function.
+ (init_data_ref): Initialize new data-ref fields.
+ (strip_conversion): Moved from tree-vect-analyze.c.
+ (analyze_offset_expr, get_ptr_offset, address_analysis, object_analysis):
+ Likewise.
+ (analyze_offset): New function.
+ (create_data_ref): Likewise.
+ (initialize_data_dependence_relation): Call base_addr_differ_p. Compare
+ dimensions for ARRAY_REFs only.
+ (build_classic_dist_vector): Make static.
+ (access_functions_are_affine_or_constant_p): Call macro to get the
+ address of access functions.
+ (compute_all_dependences): Add new parameter
+ compute_self_and_read_read_dependences. Compute self and read-read
+ dependences if it is true.
+ (find_data_references_in_loop): Call create_data_ref. Initialize new
+ data-ref fields.
+ (compute_data_dependences_for_loop): Add new parameter
+ compute_self_and_read_read_dependences. Remove parameter nb_loops,
+ compute nb_loops. Call compute_all_dependences, build_classic_dist_vector
+ and build_classic_dir_vector with correct parameters.
+ (analyze_all_data_dependences): Call compute_data_dependences_for_loop with
+ correct parameters. Compare dimensions for ARRAY_REFs only.
+ (free_data_refs): Call macro to free access functions.
+ * tree-data-ref.h (struct first_location_in_loop): New structure. Move
+ fields from stmt_vinfo.
+ (struct base_object_info): New structure.
+ (struct data_reference): Move fields to base_object_info. Add fields
+ first_location and object_info for above structures. Move fields from
+ stmt_info: memtag, ptr_info, subvars, misalignment. Add new field aligned_to.
+ Add macros to access the new fields.
+ Update functions declarations.
+ * tree-flow.h (is_aliased_with): Declare.
+ * tree-loop-linear.c (linear_transform_loops): Call
+ compute_data_dependences_for_loop with correct parameters.
+ * tree-ssa-alias.c (is_aliased_with): New function.
+ * tree-vect-analyze.c (vect_get_ptr_offset): Remove.
+ (vect_analyze_offset_expr, vect_base_addr_differ_p): Likewise.
+ (vect_analyze_data_ref_dependence): Get ddr. Remove call to
+ vect_base_addr_differ_p, compute_subscript_distance and
+ build_classic_dist_vector. Add printings. Check absolute value of
+ distance.
+ (vect_analyze_data_ref_dependences): Go through ddrs instead of data-refs.
+ (vect_compute_data_ref_alignment): Get the fields of data-ref instead of
+ stmt. Check aligned_to. Check if the base is aligned. Remove conversion
+ to bytes. Add printing.
+ (vect_compute_data_refs_alignment): Go through loads and stores in one loop.
+ (vect_enhance_data_refs_alignment, vect_analyze_data_refs_alignment,
+ vect_analyze_data_ref_access): Likewise.
+ (vect_analyze_pointer_ref_access): Remove.
+ (vect_address_analysis, vect_object_analysis): Likewise.
+ (vect_analyze_data_refs): Call compute_data_dependences_for_loop to find
+ and analyze data-refs in the loop.
+ * tree-vect-transform.c (vect_create_addr_base_for_vector_ref): Get the
+ fields of data-ref instead of stmt. Add init to the offset from the base.
+ (vect_create_data_ref_ptr): Get the fields of data-ref instead of stmt.
+ (vect_update_init_of_dr): Likewise.
+ (vect_update_inits_of_drs): Go through loads and stores in one loop.
+ * tree-vectorizer.c (new_stmt_vec_info): Remove initialization of removed
+ fields.
+ (new_loop_vec_info): Initialize new fields.
+ (destroy_loop_vec_info): Free new fields.
+ (vect_strip_conversion): Remove.
+ * tree-vectorizer.h (enum verbosity_levels): Add new verbosity level.
+ (struct _loop_vec_info): Unify data_ref_writes and data_ref_reads into
+ datarefs. Add new field ddrs.
+ Add macros for the new fields access.
+ (struct _stmt_vec_info): Remove: base_address, initial_offset, step,
+ base_aligned_p, misalignment, memtag, ptr_info and subvars.
+ Remove their macros.
+ * tree.h (highest_pow2_factor): Declare.
+
2005-07-25 Jakub Jelinek <jakub@redhat.com>
* calls.c (store_one_arg): Check for sibling call MEM arguments
diff --git a/gcc/expr.c b/gcc/expr.c
index 60d45f3..c263ebf 100644
--- a/gcc/expr.c
+++ b/gcc/expr.c
@@ -145,7 +145,6 @@ static void store_constructor (tree, rtx, int, HOST_WIDE_INT);
static rtx store_field (rtx, HOST_WIDE_INT, HOST_WIDE_INT, enum machine_mode,
tree, tree, int);
-static unsigned HOST_WIDE_INT highest_pow2_factor (tree);
static unsigned HOST_WIDE_INT highest_pow2_factor_for_target (tree, tree);
static int is_aligning_offset (tree, tree);
@@ -6047,7 +6046,7 @@ safe_from_p (rtx x, tree exp, int top_p)
/* Return the highest power of two that EXP is known to be a multiple of.
This is used in updating alignment of MEMs in array references. */
-static unsigned HOST_WIDE_INT
+unsigned HOST_WIDE_INT
highest_pow2_factor (tree exp)
{
unsigned HOST_WIDE_INT c0, c1;
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index a5d540c..4656f1b 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,19 @@
+2005-07-25 Ira Rosen <irar@il.ibm.com>
+
+ * gcc.dg/vect/vect.exp: Change verbosity level to 4.
+ * gfortran.dg/vect/vect.exp, g++.dg/vect/vect.exp: Likewise.
+ * gcc.dg/vect/pr20122.c: Add vectorizable version of the loop.
+ * gcc.dg/vect/vect-100.c: New test.
+ * gcc.dg/vect/vect-101.c, gcc.dg/vect/vect-102.c,
+ gcc.dg/vect/vect-103.c, gcc.dg/vect/vect-104.c,
+ gcc.dg/vect/vect-105.c, gcc.dg/vect/vect-115.c: Likewise.
+ * gcc.dg/vect/vect-116.c: Renamed (from vect-100.c).
+ * gcc.dg/vect/vect-43.c: Add vectorizable version of the loop.
+ * gcc.dg/vect/vect-91.c: Now 3 loops are vectorizable.
+ * gfortran.dg/vect/vect-4.f90: Now vectorizable.
+ * gfortran.dg/vect/pr19049.f90: New testcase.
+ * g++.dg/vect/pr21218.cc, gcc.dg/tree-ssa/ltrans-8.c: Likewise.
+
2005-07-25 Jakub Jelinek <jakub@redhat.com>
* gcc.c-torture/execute/20050713-1.c: New test.
diff --git a/gcc/testsuite/g++.dg/vect/pr21218.cc b/gcc/testsuite/g++.dg/vect/pr21218.cc
new file mode 100644
index 0000000..73331d2
--- /dev/null
+++ b/gcc/testsuite/g++.dg/vect/pr21218.cc
@@ -0,0 +1,18 @@
+/* { dg-do compile } */
+
+struct A
+{
+ double d[2];
+ double foo(int i) { return d[i]; }
+};
+
+struct B : public A {};
+
+void bar(B& b)
+{
+ for (int i=0; i<2; ++i)
+ b.d[i] = b.foo(i);
+}
+
+/* { dg-final { cleanup-tree-dump "vect" } } */
+
diff --git a/gcc/testsuite/g++.dg/vect/vect.exp b/gcc/testsuite/g++.dg/vect/vect.exp
index 1a084d0..f363101 100644
--- a/gcc/testsuite/g++.dg/vect/vect.exp
+++ b/gcc/testsuite/g++.dg/vect/vect.exp
@@ -40,7 +40,7 @@ set DEFAULT_VECTCFLAGS ""
# These flags are used for all targets.
lappend DEFAULT_VECTCFLAGS "-O2" "-ftree-vectorize" \
- "-ftree-vectorizer-verbose=3" "-fdump-tree-vect-stats"
+ "-ftree-vectorizer-verbose=4" "-fdump-tree-vect-stats"
# Skip these tests for targets that do not support generating vector
# code. Set additional target-dependent vector flags, which can be
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ltrans-8.c b/gcc/testsuite/gcc.dg/tree-ssa/ltrans-8.c
new file mode 100644
index 0000000..80c9c01
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/ltrans-8.c
@@ -0,0 +1,13 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -ftree-loop-linear -fdump-tree-ltrans-all" } */
+double foo(double *a)
+{
+ int i,j;
+ double r = 0.0;
+ for (i=0; i<8; ++i)
+ for (j=0; j<8; ++j)
+ r += a[j*8+i];
+ return r;
+}
+
+/* { dg-final { scan-tree-dump-times "transformed loop" 1 "ltrans"} } */
diff --git a/gcc/testsuite/gcc.dg/vect/pr20122.c b/gcc/testsuite/gcc.dg/vect/pr20122.c
index 7fef988..a713e5e 100644
--- a/gcc/testsuite/gcc.dg/vect/pr20122.c
+++ b/gcc/testsuite/gcc.dg/vect/pr20122.c
@@ -7,8 +7,10 @@ typedef short ashort __attribute__ ((__aligned__(16)));
ashort Kernshort[24];
static void VecBug(ashort Kernel[8][24]) __attribute__((noinline));
static void VecBug(ashort Kernel[8][24]);
+static void VecBug2(ashort Kernel[8][24]) __attribute__((noinline));
+static void VecBug2(ashort Kernel[8][24]);
-/* Doesn't occur of only inner-loop. */
+/* Not vectorizable: Kernel may alias Kernshort - a global array. */
static void VecBug(ashort Kernel[8][24])
{
int k,i;
@@ -17,6 +19,21 @@ static void VecBug(ashort Kernel[8][24])
Kernshort[i] = Kernel[k][i];
}
+/* Vectorizable: Kernshort2 is local. */
+static void VecBug2(ashort Kernel[8][24])
+{
+ int k,i;
+ ashort Kernshort2[24];
+ for (k = 0; k<8; k++)
+ for (i = 0; i<24; i++)
+ Kernshort2[i] = Kernel[k][i];
+
+ for (k = 0; k<8; k++)
+ for (i = 0; i<24; i++)
+ if (Kernshort2[i] != Kernel[k][i])
+ abort ();
+}
+
int main (int argc, char **argv)
{
check_vect ();
@@ -29,6 +46,7 @@ int main (int argc, char **argv)
Kernel[k][i] = 0;
VecBug(Kernel);
+ VecBug2(Kernel);
return 0;
}
diff --git a/gcc/testsuite/gcc.dg/vect/vect-100.c b/gcc/testsuite/gcc.dg/vect/vect-100.c
index 3b803fc..c1b9e40 100644
--- a/gcc/testsuite/gcc.dg/vect/vect-100.c
+++ b/gcc/testsuite/gcc.dg/vect/vect-100.c
@@ -1,28 +1,78 @@
-/* Assuming we can vectorize char multiplication, here's an execute test. */
+/* { dg-require-effective-target vect_int } */
+#include <stdlib.h>
#include <stdarg.h>
#include "tree-vect.h"
-extern void abort (void);
-void foo()
+#define N 9
+
+struct extraction
{
- static unsigned char A[256], B[256], C[256];
+ int a[N];
+ int b[N];
+};
+
+static int a[N] = {1,2,3,4,5,6,7,8,9};
+static int b[N] = {2,3,4,5,6,7,8,9,0};
+
+int main1 () {
int i;
+ struct extraction *p;
+
+ p = (struct extraction *) malloc (sizeof (struct extraction));
- for (i = 0; i < 256; ++i)
- A[i] = B[i] = i;
+ /* Not vectorizable: p may alias a and/or b, since they are globals. */
+ for (i = 0; i < N; i++)
+ {
+ p->a[i] = a[i];
+ p->b[i] = b[i];
+ }
- for (i = 0; i < 256; ++i)
- C[i] = A[i] * B[i];
+ /* check results: */
+ for (i = 0; i < N; i++)
+ {
+ if (p->a[i] != a[i] || p->b[i] != b[i])
+ abort();
+ }
- for (i = 0; i < 256; ++i)
- if (C[i] != (unsigned char)(i * i))
- abort ();
+ return 0;
}
-int main()
-{
- check_vect ();
- foo();
+int main2 () {
+ int i;
+ int c[N] = {1,2,3,4,5,6,7,8,9};
+ int d[N] = {2,3,4,5,6,7,8,9,0};
+ struct extraction *p;
+ p = (struct extraction *) malloc (sizeof (struct extraction));
+
+ /* Vectorizable: c and d are local arrays. */
+ for (i = 0; i < N; i++)
+ {
+ p->a[i] = c[i];
+ p->b[i] = d[i];
+ }
+
+ /* check results: */
+ for (i = 0; i < N; i++)
+ {
+ if (p->a[i] != c[i] || p->b[i] != d[i])
+ abort();
+ }
+
return 0;
}
+
+int main (void)
+{
+ check_vect ();
+
+ main1 ();
+ main2 ();
+
+ return 0;
+}
+
+/* Requires versioning. */
+/* { dg-final { scan-tree-dump-times "vectorized 1 loops" 0 "vect" } } */
+/* { dg-final { cleanup-tree-dump "vect" } } */
+
diff --git a/gcc/testsuite/gcc.dg/vect/vect-101.c b/gcc/testsuite/gcc.dg/vect/vect-101.c
new file mode 100644
index 0000000..e195a58
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/vect/vect-101.c
@@ -0,0 +1,49 @@
+/* { dg-require-effective-target vect_int } */
+
+#include <stdlib.h>
+#include <stdarg.h>
+#include "tree-vect.h"
+
+#define N 9
+
+struct extraction
+{
+ int a[N];
+ int b[N];
+};
+
+static int a[N] = {1,2,3,4,5,6,7,8,9};
+static int b[N] = {2,3,4,5,6,7,8,9,0};
+
+int main1 (int x, int y) {
+ int i;
+ struct extraction *p;
+ p = (struct extraction *) malloc (sizeof (struct extraction));
+
+ /* Not vectorizable: different unknown offset. */
+ for (i = 0; i < N; i++)
+ {
+ *((int *)p + x + i) = a[i];
+ *((int *)p + y + i) = b[i];
+ }
+
+ /* check results: */
+ for (i = 0; i < N; i++)
+ {
+ if (p->a[i] != a[i] || p->b[i] != b[i])
+ abort();
+ }
+ return 0;
+}
+
+int main (void)
+{
+ check_vect ();
+
+ return main1 (0, N);
+}
+
+/* { dg-final { scan-tree-dump-times "vectorized 1 loops" 0 "vect" } } */
+/* { dg-final { scan-tree-dump-times "can't determine dependence" 1 "vect" } } */
+/* { dg-final { cleanup-tree-dump "vect" } } */
+
diff --git a/gcc/testsuite/gcc.dg/vect/vect-102.c b/gcc/testsuite/gcc.dg/vect/vect-102.c
new file mode 100644
index 0000000..af3261d
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/vect/vect-102.c
@@ -0,0 +1,55 @@
+/* { dg-require-effective-target vect_int } */
+
+#include <stdlib.h>
+#include <stdarg.h>
+#include "tree-vect.h"
+
+#define N 9
+
+struct extraction
+{
+ int a[N];
+ int b[N];
+};
+
+static int a[N] = {1,2,3,4,5,6,7,8,9};
+static int b[N] = {2,3,4,5,6,7,8,9,9};
+
+int main1 (int x, int y) {
+ int i;
+ struct extraction *p;
+ p = (struct extraction *) malloc (sizeof (struct extraction));
+
+ for (i = 0; i < N; i++)
+ {
+ p->a[i] = a[i];
+ if (x == 135)
+ abort (); /* to avoid vectorization */
+ }
+
+ /* Not vectorizable: distance 1. */
+ for (i = 0; i < N - 1; i++)
+ {
+ *((int *)p + x + i) = *((int *)p + x + i + 1);
+ }
+
+ /* check results: */
+ for (i = 0; i < N; i++)
+ {
+ if (p->a[i] != b[i])
+ abort();
+ }
+ return 0;
+}
+
+int main (void)
+{
+ check_vect ();
+
+ return main1 (0, N);
+}
+
+/* { dg-final { scan-tree-dump-times "vectorized 1 loops" 0 "vect" } } */
+/* { dg-final { scan-tree-dump-times "possible dependence between data-refs" 1 "vect" } } */
+/* { dg-final { cleanup-tree-dump "vect" } } */
+
diff --git a/gcc/testsuite/gcc.dg/vect/vect-103.c b/gcc/testsuite/gcc.dg/vect/vect-103.c
new file mode 100644
index 0000000..effa97e
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/vect/vect-103.c
@@ -0,0 +1,57 @@
+/* { dg-require-effective-target vect_int } */
+
+#include <stdlib.h>
+#include <stdarg.h>
+#include "tree-vect.h"
+
+#define N 9
+
+struct extraction
+{
+ int a[N];
+ int b[N];
+};
+
+static int a[N] = {1,2,3,4,5,6,7,8,9};
+static int b[N] = {17,24,7,0,2,3,4,31,82};
+static int c[N] = {9,17,24,7,0,2,3,4,31};
+
+int main1 (int x, int y) {
+ int i;
+ struct extraction *p;
+ p = (struct extraction *) malloc (sizeof (struct extraction));
+
+ for (i = 0; i < N; i++)
+ {
+ p->a[i] = a[i];
+ p->b[i] = b[i];
+ if (x == 135)
+ abort (); /* to avoid vectorization */
+ }
+
+ /* Vectorizable: distance > VF. */
+ for (i = 0; i < N; i++)
+ {
+ *((int *)p + x + i) = *((int *)p + x + i + 8);
+ }
+
+ /* check results: */
+ for (i = 0; i < N; i++)
+ {
+ if (p->a[i] != c[i])
+ abort();
+ }
+ return 0;
+}
+
+int main (void)
+{
+ check_vect ();
+
+ return main1 (0, N);
+}
+
+/* { dg-final { scan-tree-dump-times "vectorized 1 loops" 1 "vect" } } */
+/* { dg-final { scan-tree-dump-times "dependence distance modulo vf == 0" 1 "vect" } } */
+/* { dg-final { cleanup-tree-dump "vect" } } */
+
diff --git a/gcc/testsuite/gcc.dg/vect/vect-104.c b/gcc/testsuite/gcc.dg/vect/vect-104.c
new file mode 100644
index 0000000..6d16da6
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/vect/vect-104.c
@@ -0,0 +1,66 @@
+/* { dg-require-effective-target vect_int } */
+
+#include <stdlib.h>
+#include <stdarg.h>
+#include "tree-vect.h"
+
+#define N 3
+
+struct extraction
+{
+ int a[N][N];
+ int b[N][N];
+};
+
+static int a[N][N] = {{1,2,3},{4,5,6},{7,8,9}};
+static int b[N][N] = {{17,24,7},{0,2,3},{4,31,82}};
+static int c[N][N] = {{1,2,3},{4,6,8},{8,9,9}};
+
+int main1 (int x) {
+ int i,j;
+ struct extraction *p;
+ p = (struct extraction *) malloc (sizeof (struct extraction));
+
+ for (i = 0; i < N; i++)
+ {
+ for (j = 0; j < N; j++)
+ {
+ p->a[i][j] = a[i][j];
+ p->b[i][j] = b[i][j];
+ if (x == 135)
+ abort (); /* to avoid vectorization */
+ }
+ }
+
+ /* Not vectorizable: distance = 1. */
+ for (i = 1; i < N; i++)
+ {
+ for (j = 0; j < N; j++)
+ {
+ *((int *)p + x + i + j) = *((int *)p + x + i + j + 1);
+ }
+ }
+
+ /* check results: */
+ for (i = 0; i < N; i++)
+ {
+ for (j = 0; j < N; j++)
+ {
+ if (p->a[i][j] != c[i][j])
+ abort();
+ }
+ }
+ return 0;
+}
+
+int main (void)
+{
+ check_vect ();
+
+ return main1 (N);
+}
+
+/* { dg-final { scan-tree-dump-times "vectorized 1 loops" 0 "vect" } } */
+/* { dg-final { scan-tree-dump-times "possible dependence between data-refs" 1 "vect" } } */
+/* { dg-final { cleanup-tree-dump "vect" } } */
+
diff --git a/gcc/testsuite/gcc.dg/vect/vect-105.c b/gcc/testsuite/gcc.dg/vect/vect-105.c
new file mode 100644
index 0000000..c8f8e5b
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/vect/vect-105.c
@@ -0,0 +1,66 @@
+/* { dg-require-effective-target vect_int } */
+
+#include <stdlib.h>
+#include <stdarg.h>
+#include "tree-vect.h"
+
+#define N 4
+
+struct extraction
+{
+ int a[N][N];
+ int b[N][N];
+};
+
+static int a[N][N] = {{1,2,3,11},{4,5,6,12},{7,8,9,13},{34,45,67,83}};
+static int b[N][N] = {{17,28,15,23},{0,2,3,24},{4,31,82,25},{29,31,432,256}};
+static int c[N][N] = {{1,2,3,11},{4,9,13,34},{45,67,83,13},{34,45,67,83}};
+
+int main1 (int x) {
+ int i,j;
+ struct extraction *p;
+ p = (struct extraction *) malloc (sizeof (struct extraction));
+
+ for (i = 0; i < N; i++)
+ {
+ for (j = 0; j < N; j++)
+ {
+ p->a[i][j] = a[i][j];
+ p->b[i][j] = b[i][j];
+ if (x == 135)
+ abort (); /* to avoid vectorization */
+ }
+ }
+
+ /* Vectorizable: distance > number of iterations. */
+ for (i = 1; i < N; i++)
+ {
+ for (j = 0; j < N; j++)
+ {
+ *((int *)p + x + i + j) = *((int *)p + x + i + j + 5);
+ }
+ }
+
+ /* check results: */
+ for (i = 0; i < N; i++)
+ {
+ for (j = 0; j < N; j++)
+ {
+ if (p->a[i][j] != c[i][j])
+ abort();
+ }
+ }
+ return 0;
+}
+
+int main (void)
+{
+ check_vect ();
+
+ return main1 (N);
+}
+
+/* { dg-final { scan-tree-dump-times "vectorized 1 loops" 1 "vect" } } */
+/* { dg-final { scan-tree-dump-times "possible dependence between data-refs" 0 "vect" } } */
+/* { dg-final { cleanup-tree-dump "vect" } } */
+
diff --git a/gcc/testsuite/gcc.dg/vect/vect-115.c b/gcc/testsuite/gcc.dg/vect/vect-115.c
new file mode 100644
index 0000000..fe055fb
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/vect/vect-115.c
@@ -0,0 +1,75 @@
+/* { dg-require-effective-target vect_int } */
+
+#include <stdarg.h>
+#include "tree-vect.h"
+
+#define N 16
+
+struct s{
+ int b[N];
+ int c[N];
+ int m;
+};
+
+struct t{
+ struct s strc_s;
+ int m;
+};
+
+struct test1{
+ struct t strc_t;
+ struct t *ptr_t;
+ int k;
+ int l;
+};
+
+int main1 ()
+{
+ int i;
+ struct test1 tmp1;
+ int a[N] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
+ struct t tmp2;
+
+ tmp1.ptr_t = &tmp2;
+
+ /* DR bases comparison: record and array. */
+ for (i = 0; i < N; i++)
+ {
+ tmp1.strc_t.strc_s.b[i] = a[i];
+ }
+
+ /* Check results. */
+ for (i = 0; i < N; i++)
+ {
+ if (tmp1.strc_t.strc_s.b[i] != a[i])
+ abort();
+ }
+
+ /* DR bases comparison: record containing ptr and array. */
+ for (i = 0; i < N; i++)
+ {
+ tmp1.ptr_t->strc_s.c[i] = a[i];
+ }
+
+ /* Check results. */
+ for (i = 0; i < N; i++)
+ {
+ if (tmp1.ptr_t->strc_s.c[i] != a[i])
+ abort();
+ }
+
+
+ return 0;
+}
+
+int main (void)
+{
+ check_vect ();
+
+ return main1 ();
+}
+
+/* { dg-final { scan-tree-dump-times "vectorized 2 loops" 1 "vect" } } */
+/* { dg-final { cleanup-tree-dump "vect" } } */
+
+
diff --git a/gcc/testsuite/gcc.dg/vect/vect-116.c b/gcc/testsuite/gcc.dg/vect/vect-116.c
new file mode 100644
index 0000000..3b803fc
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/vect/vect-116.c
@@ -0,0 +1,28 @@
+/* Assuming we can vectorize char multiplication, here's an execute test. */
+
+#include <stdarg.h>
+#include "tree-vect.h"
+
+extern void abort (void);
+void foo()
+{
+ static unsigned char A[256], B[256], C[256];
+ int i;
+
+ for (i = 0; i < 256; ++i)
+ A[i] = B[i] = i;
+
+ for (i = 0; i < 256; ++i)
+ C[i] = A[i] * B[i];
+
+ for (i = 0; i < 256; ++i)
+ if (C[i] != (unsigned char)(i * i))
+ abort ();
+}
+
+int main()
+{
+ check_vect ();
+ foo();
+ return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/vect/vect-43.c b/gcc/testsuite/gcc.dg/vect/vect-43.c
index 6cea832..12db333 100644
--- a/gcc/testsuite/gcc.dg/vect/vect-43.c
+++ b/gcc/testsuite/gcc.dg/vect/vect-43.c
@@ -29,7 +29,7 @@ main1 (afloat * pa)
afloat pb[N] = {0,3,6,9,12,15,18,21,24,27,30,33,36,39,42,45,48,51,54,57};
afloat pc[N] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19};
-
+ /* Not vectorizable: pa may alias pb and/or pc, since their addresses escape. */
for (i = 0; i < N; i++)
{
pa[i] = pb[i] * pc[i];
@@ -40,6 +40,29 @@ main1 (afloat * pa)
return 0;
}
+int
+main2 (afloat * pa)
+{
+ int i;
+ afloat pb[N] = {0,3,6,9,12,15,18,21,24,27,30,33,36,39,42,45,48,51,54,57};
+ afloat pc[N] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19};
+
+ /* Vectorizable: pb and pc addresses do not escape. */
+ for (i = 0; i < N; i++)
+ {
+ pa[i] = pb[i] * pc[i];
+ }
+
+ /* check results: */
+ for (i = 0; i < N; i++)
+ {
+ if (pa[i] != (pb[i] * pc[i]))
+ abort ();
+ }
+
+ return 0;
+}
+
int main (void)
{
int i;
@@ -50,6 +73,7 @@ int main (void)
check_vect ();
main1 (a);
+ main2 (a);
return 0;
}
diff --git a/gcc/testsuite/gcc.dg/vect/vect-91.c b/gcc/testsuite/gcc.dg/vect/vect-91.c
index 96099f4..d72bd4c 100644
--- a/gcc/testsuite/gcc.dg/vect/vect-91.c
+++ b/gcc/testsuite/gcc.dg/vect/vect-91.c
@@ -11,10 +11,7 @@ extern int a[N];
/* The alignment of 'pa' is unknown.
Yet we do know that both the read access and write access have
the same alignment. Peeling to align one of the accesses will
- align the other.
-
- Not vectorized yet due to problems in dataref analysis that
- are fixed in autovect-branch but not yet in mainline. */
+ align the other. */
int
main1 (int * pa)
@@ -60,11 +57,8 @@ main3 ()
return 0;
}
-/* Currently only the loops in main2 and main3 get vectorized. After the merge
- of the datarefs-analysis cleanups from autovect-branch to mainline, the loop
- in main1 will also be vectorized. */
-/* { dg-final { scan-tree-dump-times "vectorized 1 loops" 2 "vect" { xfail vect_no_int_add } } } */
+/* { dg-final { scan-tree-dump-times "vectorized 1 loops" 3 "vect" } } */
/* { dg-final { scan-tree-dump-times "Vectorizing an unaligned access" 0 "vect" } } */
-/* { dg-final { scan-tree-dump-times "accesses have the same alignment." 2 "vect" } } */
-/* { dg-final { scan-tree-dump-times "Alignment of access forced using peeling" 2 "vect" } } */
+/* { dg-final { scan-tree-dump-times "accesses have the same alignment." 3 "vect" } } */
+/* { dg-final { scan-tree-dump-times "Alignment of access forced using peeling" 3 "vect" } } */
/* { dg-final { cleanup-tree-dump "vect" } } */
diff --git a/gcc/testsuite/gcc.dg/vect/vect.exp b/gcc/testsuite/gcc.dg/vect/vect.exp
index 8c53541..07b7e94 100644
--- a/gcc/testsuite/gcc.dg/vect/vect.exp
+++ b/gcc/testsuite/gcc.dg/vect/vect.exp
@@ -24,7 +24,7 @@ set DEFAULT_VECTCFLAGS ""
# These flags are used for all targets.
lappend DEFAULT_VECTCFLAGS "-O2" "-ftree-vectorize" \
- "-ftree-vectorizer-verbose=3" "-fdump-tree-vect-stats"
+ "-ftree-vectorizer-verbose=4" "-fdump-tree-vect-stats"
# If the target system supports vector instructions, the default action
# for a test is 'run', otherwise it's 'compile'. Save current default.
diff --git a/gcc/testsuite/gfortran.dg/vect/pr19049.f90 b/gcc/testsuite/gfortran.dg/vect/pr19049.f90
new file mode 100644
index 0000000..6c8030c
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/vect/pr19049.f90
@@ -0,0 +1,24 @@
+! { dg-do compile }
+! { dg-require-effective-target vect_float }
+
+subroutine s111 (ntimes,ld,n,ctime,dtime,a,b,c,d,e,aa,bb,cc)
+! linear dependence testing
+! no dependence - vectorizable
+! but not consecutive access
+
+ integer ntimes, ld, n, i, nl
+ real a(n), b(n), c(n), d(n), e(n), aa(ld,n), bb(ld,n), cc(ld,n)
+ real t1, t2, second, chksum, ctime, dtime, cs1d
+ do 1 nl = 1,2*ntimes
+ do 10 i = 2,n,2
+ a(i) = a(i-1) + b(i)
+ 10 continue
+ call dummy(ld,n,a,b,c,d,e,aa,bb,cc,1.)
+ 1 continue
+ return
+ end
+
+! { dg-final { scan-tree-dump-times "vectorized 1 loops" 0 "vect" } }
+! { dg-final { scan-tree-dump-times "complicated access pattern" 1 "vect" } }
+! { dg-final { cleanup-tree-dump "vect" } }
+
diff --git a/gcc/testsuite/gfortran.dg/vect/vect-4.f90 b/gcc/testsuite/gfortran.dg/vect/vect-4.f90
index e83c05c..74f4e97 100644
--- a/gcc/testsuite/gfortran.dg/vect/vect-4.f90
+++ b/gcc/testsuite/gfortran.dg/vect/vect-4.f90
@@ -9,10 +9,8 @@ DIMENSION X(64), Y(64)
Y = Y + A * X
END
-! fail to vectorize due to aliasing problems in dataref analysis that are
-! solved in autvect-branch but not yet in mainline.
-! { dg-final { scan-tree-dump-times "vectorized 1 loops" 1 "vect" { xfail *-*-* } } }
-! { dg-final { scan-tree-dump-times "Alignment of access forced using peeling" 1 "vect" { xfail *-*-* } } }
-! { dg-final { scan-tree-dump-times "Vectorizing an unaligned access" 1 "vect" { xfail *-*-* } } }
-! { dg-final { scan-tree-dump-times "accesses have the same alignment." 1 "vect" { xfail *-*-* } } }
+! { dg-final { scan-tree-dump-times "vectorized 1 loops" 1 "vect" } }
+! { dg-final { scan-tree-dump-times "Alignment of access forced using peeling" 1 "vect" } }
+! { dg-final { scan-tree-dump-times "Vectorizing an unaligned access" 1 "vect" } }
+! { dg-final { scan-tree-dump-times "accesses have the same alignment." 1 "vect" } }
! { dg-final { cleanup-tree-dump "vect" } }
diff --git a/gcc/testsuite/gfortran.dg/vect/vect.exp b/gcc/testsuite/gfortran.dg/vect/vect.exp
index dfaaeb9..7f1ec2d 100644
--- a/gcc/testsuite/gfortran.dg/vect/vect.exp
+++ b/gcc/testsuite/gfortran.dg/vect/vect.exp
@@ -25,7 +25,7 @@ set DEFAULT_VECTCFLAGS ""
# These flags are used for all targets.
lappend DEFAULT_VECTCFLAGS "-O2" "-ftree-vectorize" \
- "-ftree-vectorizer-verbose=3" "-fdump-tree-vect-stats"
+ "-ftree-vectorizer-verbose=4" "-fdump-tree-vect-stats"
# If the target system supports vector instructions, the default action
# for a test is 'run', otherwise it's 'compile'. Save current default.
diff --git a/gcc/tree-data-ref.c b/gcc/tree-data-ref.c
index d48f020..05361a2 100644
--- a/gcc/tree-data-ref.c
+++ b/gcc/tree-data-ref.c
@@ -94,6 +94,180 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
#include "tree-scalar-evolution.h"
#include "tree-pass.h"
+static tree object_analysis (tree, tree, bool, struct data_reference **,
+ tree *, tree *, tree *, tree *, tree *,
+ struct ptr_info_def **, subvar_t *);
+static struct data_reference * init_data_ref (tree, tree, tree, tree, bool,
+ tree, tree, tree, tree, tree,
+ struct ptr_info_def *,
+ enum data_ref_type);
+
+/* Determine if PTR and DECL may alias, the result is put in ALIASED.
+ Return FALSE if there is no type memory tag for PTR.
+*/
+static bool
+ptr_decl_may_alias_p (tree ptr, tree decl,
+ struct data_reference *ptr_dr,
+ bool *aliased)
+{
+ tree tag;
+
+ gcc_assert (TREE_CODE (ptr) == SSA_NAME && DECL_P (decl));
+
+ tag = get_var_ann (SSA_NAME_VAR (ptr))->type_mem_tag;
+ if (!tag)
+ tag = DR_MEMTAG (ptr_dr);
+ if (!tag)
+ return false;
+
+ *aliased = is_aliased_with (tag, decl);
+ return true;
+}
+
+
+/* Determine if two pointers may alias, the result is put in ALIASED.
+ Return FALSE if there is no type memory tag for one of the pointers.
+*/
+static bool
+ptr_ptr_may_alias_p (tree ptr_a, tree ptr_b,
+ struct data_reference *dra,
+ struct data_reference *drb,
+ bool *aliased)
+{
+ tree tag_a, tag_b;
+
+ tag_a = get_var_ann (SSA_NAME_VAR (ptr_a))->type_mem_tag;
+ if (!tag_a)
+ tag_a = DR_MEMTAG (dra);
+ if (!tag_a)
+ return false;
+ tag_b = get_var_ann (SSA_NAME_VAR (ptr_b))->type_mem_tag;
+ if (!tag_b)
+ tag_b = DR_MEMTAG (drb);
+ if (!tag_b)
+ return false;
+ *aliased = (tag_a == tag_b);
+ return true;
+}
+
+
+/* Determine if BASE_A and BASE_B may alias, the result is put in ALIASED.
+ Return FALSE if there is no type memory tag for one of the symbols.
+*/
+static bool
+may_alias_p (tree base_a, tree base_b,
+ struct data_reference *dra,
+ struct data_reference *drb,
+ bool *aliased)
+{
+ if (TREE_CODE (base_a) == ADDR_EXPR || TREE_CODE (base_b) == ADDR_EXPR)
+ {
+ if (TREE_CODE (base_a) == ADDR_EXPR && TREE_CODE (base_b) == ADDR_EXPR)
+ {
+ *aliased = (TREE_OPERAND (base_a, 0) == TREE_OPERAND (base_b, 0));
+ return true;
+ }
+ if (TREE_CODE (base_a) == ADDR_EXPR)
+ return ptr_decl_may_alias_p (base_b, TREE_OPERAND (base_a, 0), drb,
+ aliased);
+ else
+ return ptr_decl_may_alias_p (base_a, TREE_OPERAND (base_b, 0), dra,
+ aliased);
+ }
+
+ return ptr_ptr_may_alias_p (base_a, base_b, dra, drb, aliased);
+}
+
+
+/* Determine if a pointer (BASE_A) and a record/union access (BASE_B)
+ are not aliased. Return TRUE if they differ. */
+static bool
+record_ptr_differ_p (struct data_reference *dra,
+ struct data_reference *drb)
+{
+ bool aliased;
+ tree base_a = DR_BASE_OBJECT (dra);
+ tree base_b = DR_BASE_OBJECT (drb);
+
+ if (TREE_CODE (base_b) != COMPONENT_REF)
+ return false;
+
+ /* Peel COMPONENT_REFs to get to the base. Do not peel INDIRECT_REFs.
+ For a.b.c.d[i] we will get a, and for a.b->c.d[i] we will get a.b.
+ Probably will be unnecessary with struct alias analysis. */
+ while (TREE_CODE (base_b) == COMPONENT_REF)
+ base_b = TREE_OPERAND (base_b, 0);
+ /* Compare a record/union access (b.c[i] or p->c[i]) and a pointer
+ ((*q)[i]). */
+ if (TREE_CODE (base_a) == INDIRECT_REF
+ && ((TREE_CODE (base_b) == VAR_DECL
+ && (ptr_decl_may_alias_p (TREE_OPERAND (base_a, 0), base_b, dra,
+ &aliased)
+ && !aliased))
+ || (TREE_CODE (base_b) == INDIRECT_REF
+ && (ptr_ptr_may_alias_p (TREE_OPERAND (base_a, 0),
+ TREE_OPERAND (base_b, 0), dra, drb,
+ &aliased)
+ && !aliased))))
+ return true;
+ else
+ return false;
+}
+
+
+/* Determine if an array access (BASE_A) and a record/union access (BASE_B)
+ are not aliased. Return TRUE if they differ. */
+static bool
+record_array_differ_p (struct data_reference *dra,
+ struct data_reference *drb)
+{
+ bool aliased;
+ tree base_a = DR_BASE_OBJECT (dra);
+ tree base_b = DR_BASE_OBJECT (drb);
+
+ if (TREE_CODE (base_b) != COMPONENT_REF)
+ return false;
+
+ /* Peel COMPONENT_REFs to get to the base. Do not peel INDIRECT_REFs.
+ For a.b.c.d[i] we will get a, and for a.b->c.d[i] we will get a.b.
+ Probably will be unnecessary with struct alias analysis. */
+ while (TREE_CODE (base_b) == COMPONENT_REF)
+ base_b = TREE_OPERAND (base_b, 0);
+
+ /* Compare a record/union access (b.c[i] or p->c[i]) and an array access
+ (a[i]). In case of p->c[i] use alias analysis to verify that p is not
+ pointing to a. */
+ if (TREE_CODE (base_a) == VAR_DECL
+ && (TREE_CODE (base_b) == VAR_DECL
+ || (TREE_CODE (base_b) == INDIRECT_REF
+ && (ptr_decl_may_alias_p (TREE_OPERAND (base_b, 0), base_a, drb,
+ &aliased)
+ && !aliased))))
+ return true;
+ else
+ return false;
+}
+
+
+/* Determine if an array access (BASE_A) and a pointer (BASE_B)
+ are not aliased. Return TRUE if they differ. */
+static bool
+array_ptr_differ_p (tree base_a, tree base_b,
+ struct data_reference *drb)
+{
+ bool aliased;
+
+ /* In case one of the bases is a pointer (a[i] and (*p)[i]), we check with the
+ help of alias analysis that p is not pointing to a. */
+ if (TREE_CODE (base_a) == VAR_DECL && TREE_CODE (base_b) == INDIRECT_REF
+ && (ptr_decl_may_alias_p (TREE_OPERAND (base_b, 0), base_a, drb, &aliased)
+ && !aliased))
+ return true;
+ else
+ return false;
+}
+
+
/* This is the simplest data dependence test: determines whether the
data references A and B access the same array/region. Returns
false when the property is not computable at compile time.
@@ -101,13 +275,14 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
utility will not be necessary when alias_sets_conflict_p will be
less conservative. */
-bool
-array_base_name_differ_p (struct data_reference *a,
- struct data_reference *b,
- bool *differ_p)
+static bool
+base_object_differ_p (struct data_reference *a,
+ struct data_reference *b,
+ bool *differ_p)
{
- tree base_a = DR_BASE_NAME (a);
- tree base_b = DR_BASE_NAME (b);
+ tree base_a = DR_BASE_OBJECT (a);
+ tree base_b = DR_BASE_OBJECT (b);
+ bool aliased;
if (!base_a || !base_b)
return false;
@@ -152,6 +327,26 @@ array_base_name_differ_p (struct data_reference *a,
return true;
}
+ /* In case one of the bases is a pointer (a[i] and (*p)[i]), we check with the
+ help of alias analysis that p is not pointing to a. */
+ if (array_ptr_differ_p (base_a, base_b, b)
+ || array_ptr_differ_p (base_b, base_a, a))
+ {
+ *differ_p = true;
+ return true;
+ }
+
+ /* If the bases are pointers ((*q)[i] and (*p)[i]), we check with the
+ help of alias analysis they don't point to the same bases. */
+ if (TREE_CODE (base_a) == INDIRECT_REF && TREE_CODE (base_b) == INDIRECT_REF
+ && (may_alias_p (TREE_OPERAND (base_a, 0), TREE_OPERAND (base_b, 0), a, b,
+ &aliased)
+ && !aliased))
+ {
+ *differ_p = true;
+ return true;
+ }
+
/* Compare two record/union bases s.a and t.b: s != t or (a != b and
s and t are not unions). */
if (TREE_CODE (base_a) == COMPONENT_REF && TREE_CODE (base_b) == COMPONENT_REF
@@ -166,13 +361,18 @@ array_base_name_differ_p (struct data_reference *a,
return true;
}
- /* Compare a record/union access and an array access. */
- if ((TREE_CODE (base_a) == VAR_DECL
- && (TREE_CODE (base_b) == COMPONENT_REF
- && TREE_CODE (TREE_OPERAND (base_b, 0)) == VAR_DECL))
- || (TREE_CODE (base_b) == VAR_DECL
- && (TREE_CODE (base_a) == COMPONENT_REF
- && TREE_CODE (TREE_OPERAND (base_a, 0)) == VAR_DECL)))
+ /* Compare a record/union access (b.c[i] or p->c[i]) and a pointer
+ ((*q)[i]). */
+ if (record_ptr_differ_p (a, b) || record_ptr_differ_p (b, a))
+ {
+ *differ_p = true;
+ return true;
+ }
+
+ /* Compare a record/union access (b.c[i] or p->c[i]) and an array access
+ (a[i]). In case of p->c[i] use alias analysis to verify that p is not
+ pointing to a. */
+ if (record_array_differ_p (a, b) || record_array_differ_p (b, a))
{
*differ_p = true;
return true;
@@ -181,6 +381,90 @@ array_base_name_differ_p (struct data_reference *a,
return false;
}
+/* Function base_addr_differ_p.
+
+ This is the simplest data dependence test: determines whether the
+ data references A and B access the same array/region. Returns
+ false when the property is not computable at compile time.
+ Otherwise return true, and DIFFER_P will record the result. This
+ utility will not be necessary when alias_sets_conflict_p will be
+ less conservative. */
+
+
+static bool
+base_addr_differ_p (struct data_reference *dra,
+ struct data_reference *drb,
+ bool *differ_p)
+{
+ tree addr_a = DR_BASE_ADDRESS (dra);
+ tree addr_b = DR_BASE_ADDRESS (drb);
+ tree type_a, type_b;
+ bool aliased;
+
+ if (!addr_a || !addr_b)
+ return false;
+
+ type_a = TREE_TYPE (addr_a);
+ type_b = TREE_TYPE (addr_b);
+
+ gcc_assert (POINTER_TYPE_P (type_a) && POINTER_TYPE_P (type_b));
+
+ /* Compare base objects first if possible. If DR_BASE_OBJECT is NULL, it means
+ that the data-ref is of INDIRECT_REF, and alias analysis will be applied to
+ reveal the dependence. */
+ if (DR_BASE_OBJECT (dra) && DR_BASE_OBJECT (drb))
+ return base_object_differ_p (dra, drb, differ_p);
+
+ /* If base addresses are the same, we check the offsets, since the access of
+ the data-ref is described by {base addr + offset} and its access function,
+ i.e., in order to decide whether the bases of data-refs are the same we
+ compare both base addresses and offsets. */
+ if (addr_a == addr_b
+ || (TREE_CODE (addr_a) == ADDR_EXPR && TREE_CODE (addr_b) == ADDR_EXPR
+ && TREE_OPERAND (addr_a, 0) == TREE_OPERAND (addr_b, 0)))
+ {
+ /* Compare offsets. */
+ tree offset_a = DR_OFFSET (dra);
+ tree offset_b = DR_OFFSET (drb);
+
+ gcc_assert (!DR_BASE_OBJECT (dra) && !DR_BASE_OBJECT (drb));
+
+ STRIP_NOPS (offset_a);
+ STRIP_NOPS (offset_b);
+
+ /* FORNOW: we only compare offsets that are MULT_EXPR, i.e., we don't handle
+ PLUS_EXPR. */
+ if ((offset_a == offset_b)
+ || (TREE_CODE (offset_a) == MULT_EXPR
+ && TREE_CODE (offset_b) == MULT_EXPR
+ && TREE_OPERAND (offset_a, 0) == TREE_OPERAND (offset_b, 0)
+ && TREE_OPERAND (offset_a, 1) == TREE_OPERAND (offset_b, 1)))
+ {
+ *differ_p = false;
+ return true;
+ }
+ }
+
+ /* Apply alias analysis. */
+ if (may_alias_p (addr_a, addr_b, dra, drb, &aliased) && !aliased)
+ {
+ *differ_p = true;
+ return true;
+ }
+
+ /* An instruction writing through a restricted pointer is "independent" of any
+ instruction reading or writing through a different pointer, in the same
+ block/scope. */
+ else if ((TYPE_RESTRICT (type_a) && !DR_IS_READ (dra))
+ || (TYPE_RESTRICT (type_b) && !DR_IS_READ (drb)))
+ {
+ *differ_p = true;
+ return true;
+ }
+ return false;
+}
+
+
/* Returns true iff A divides B. */
static inline bool
@@ -262,7 +546,7 @@ dump_data_reference (FILE *outf,
fprintf (outf, " ref: ");
print_generic_stmt (outf, DR_REF (dr), 0);
fprintf (outf, " base_name: ");
- print_generic_stmt (outf, DR_BASE_NAME (dr), 0);
+ print_generic_stmt (outf, DR_BASE_OBJECT (dr), 0);
for (i = 0; i < DR_NUM_DIMENSIONS (dr); i++)
{
@@ -546,10 +830,11 @@ analyze_array_indexes (struct loop *loop,
set to true when REF is in the right hand side of an
assignment. */
-struct data_reference *
+static struct data_reference *
analyze_array (tree stmt, tree ref, bool is_read)
{
struct data_reference *res;
+ VEC(tree,heap) *acc_fns;
if (dump_file && (dump_flags & TDF_DETAILS))
{
@@ -563,10 +848,19 @@ analyze_array (tree stmt, tree ref, bool is_read)
DR_STMT (res) = stmt;
DR_REF (res) = ref;
- DR_ACCESS_FNS (res) = VEC_alloc (tree, heap, 3);
- DR_BASE_NAME (res) = analyze_array_indexes
- (loop_containing_stmt (stmt), &(DR_ACCESS_FNS (res)), ref, stmt);
+ acc_fns = VEC_alloc (tree, heap, 3);
+ DR_BASE_OBJECT (res) = analyze_array_indexes
+ (loop_containing_stmt (stmt), &acc_fns, ref, stmt);
+ DR_TYPE (res) = ARRAY_REF_TYPE;
+ DR_SET_ACCESS_FNS (res, acc_fns);
DR_IS_READ (res) = is_read;
+ DR_BASE_ADDRESS (res) = NULL_TREE;
+ DR_OFFSET (res) = NULL_TREE;
+ DR_INIT (res) = NULL_TREE;
+ DR_STEP (res) = NULL_TREE;
+ DR_OFFSET_MISALIGNMENT (res) = NULL_TREE;
+ DR_MEMTAG (res) = NULL_TREE;
+ DR_PTR_INFO (res) = NULL;
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, ")\n");
@@ -574,6 +868,76 @@ analyze_array (tree stmt, tree ref, bool is_read)
return res;
}
+
+/* Analyze an indirect memory reference, REF, that comes from STMT.
+ IS_READ is true if this is an indirect load, and false if it is
+ an indirect store.
+ Return a new data reference structure representing the indirect_ref, or
+ NULL if we cannot describe the access function. */
+
+static struct data_reference *
+analyze_indirect_ref (tree stmt, tree ref, bool is_read)
+{
+ struct loop *loop = loop_containing_stmt (stmt);
+ tree ptr_ref = TREE_OPERAND (ref, 0);
+ tree access_fn = analyze_scalar_evolution (loop, ptr_ref);
+ tree init = initial_condition_in_loop_num (access_fn, loop->num);
+ tree base_address = NULL_TREE, evolution, step = NULL_TREE;
+ struct ptr_info_def *ptr_info = NULL;
+
+ if (TREE_CODE (ptr_ref) == SSA_NAME)
+ ptr_info = SSA_NAME_PTR_INFO (ptr_ref);
+
+ STRIP_NOPS (init);
+ if (access_fn == chrec_dont_know || !init || init == chrec_dont_know)
+ {
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ {
+ fprintf (dump_file, "\nBad access function of ptr: ");
+ print_generic_expr (dump_file, ref, TDF_SLIM);
+ fprintf (dump_file, "\n");
+ }
+ return NULL;
+ }
+
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ {
+ fprintf (dump_file, "\nAccess function of ptr: ");
+ print_generic_expr (dump_file, access_fn, TDF_SLIM);
+ fprintf (dump_file, "\n");
+ }
+
+ if (!expr_invariant_in_loop_p (loop, init))
+ {
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ fprintf (dump_file, "\ninitial condition is not loop invariant.\n");
+ }
+ else
+ {
+ base_address = init;
+ evolution = evolution_part_in_loop_num (access_fn, loop->num);
+ if (evolution != chrec_dont_know)
+ {
+ if (!evolution)
+ step = ssize_int (0);
+ else
+ {
+ if (TREE_CODE (evolution) == INTEGER_CST)
+ step = fold_convert (ssizetype, evolution);
+ else
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ fprintf (dump_file, "\nnon constant step for ptr access.\n");
+ }
+ }
+ else
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ fprintf (dump_file, "\nunknown evolution of ptr.\n");
+ }
+ return init_data_ref (stmt, ref, NULL_TREE, access_fn, is_read, base_address,
+ NULL_TREE, step, NULL_TREE, NULL_TREE,
+ ptr_info, POINTER_REF_TYPE);
+}
+
/* For a data reference REF contained in the statement STMT, initialize
a DATA_REFERENCE structure, and return it. */
@@ -582,9 +946,17 @@ init_data_ref (tree stmt,
tree ref,
tree base,
tree access_fn,
- bool is_read)
+ bool is_read,
+ tree base_address,
+ tree init_offset,
+ tree step,
+ tree misalign,
+ tree memtag,
+ struct ptr_info_def *ptr_info,
+ enum data_ref_type type)
{
struct data_reference *res;
+ VEC(tree,heap) *acc_fns;
if (dump_file && (dump_flags & TDF_DETAILS))
{
@@ -598,10 +970,19 @@ init_data_ref (tree stmt,
DR_STMT (res) = stmt;
DR_REF (res) = ref;
- DR_ACCESS_FNS (res) = VEC_alloc (tree, heap, 5);
- DR_BASE_NAME (res) = base;
+ DR_BASE_OBJECT (res) = base;
+ DR_TYPE (res) = type;
+ acc_fns = VEC_alloc (tree, heap, 3);
+ DR_SET_ACCESS_FNS (res, acc_fns);
VEC_quick_push (tree, DR_ACCESS_FNS (res), access_fn);
DR_IS_READ (res) = is_read;
+ DR_BASE_ADDRESS (res) = base_address;
+ DR_OFFSET (res) = init_offset;
+ DR_INIT (res) = NULL_TREE;
+ DR_STEP (res) = step;
+ DR_OFFSET_MISALIGNMENT (res) = misalign;
+ DR_MEMTAG (res) = memtag;
+ DR_PTR_INFO (res) = ptr_info;
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, ")\n");
@@ -611,6 +992,869 @@ init_data_ref (tree stmt,
+/* Function strip_conversions
+
+ Strip conversions that don't narrow the mode. */
+
+static tree
+strip_conversion (tree expr)
+{
+ tree to, ti, oprnd0;
+
+ while (TREE_CODE (expr) == NOP_EXPR || TREE_CODE (expr) == CONVERT_EXPR)
+ {
+ to = TREE_TYPE (expr);
+ oprnd0 = TREE_OPERAND (expr, 0);
+ ti = TREE_TYPE (oprnd0);
+
+ if (!INTEGRAL_TYPE_P (to) || !INTEGRAL_TYPE_P (ti))
+ return NULL_TREE;
+ if (GET_MODE_SIZE (TYPE_MODE (to)) < GET_MODE_SIZE (TYPE_MODE (ti)))
+ return NULL_TREE;
+
+ expr = oprnd0;
+ }
+ return expr;
+}
+
+
+/* Function analyze_offset_expr
+
+ Given an offset expression EXPR received from get_inner_reference, analyze
+ it and create an expression for INITIAL_OFFSET by substituting the variables
+ of EXPR with initial_condition of the corresponding access_fn in the loop.
+ E.g.,
+ for i
+ for (j = 3; j < N; j++)
+ a[j].b[i][j] = 0;
+
+ For a[j].b[i][j], EXPR will be 'i * C_i + j * C_j + C'. 'i' cannot be
+ substituted, since its access_fn in the inner loop is i. 'j' will be
+ substituted with 3. An INITIAL_OFFSET will be 'i * C_i + C`', where
+ C` = 3 * C_j + C.
+
+ Compute MISALIGN (the misalignment of the data reference initial access from
+ its base). Misalignment can be calculated only if all the variables can be
+ substituted with constants, otherwise, we record maximum possible alignment
+ in ALIGNED_TO. In the above example, since 'i' cannot be substituted, MISALIGN
+ will be NULL_TREE, and the biggest divider of C_i (a power of 2) will be
+ recorded in ALIGNED_TO.
+
+ STEP is an evolution of the data reference in this loop in bytes.
+ In the above example, STEP is C_j.
+
+ Return FALSE, if the analysis fails, e.g., there is no access_fn for a
+ variable. In this case, all the outputs (INITIAL_OFFSET, MISALIGN, ALIGNED_TO
+ and STEP) are NULL_TREEs. Otherwise, return TRUE.
+
+*/
+
+static bool
+analyze_offset_expr (tree expr,
+ struct loop *loop,
+ tree *initial_offset,
+ tree *misalign,
+ tree *aligned_to,
+ tree *step)
+{
+ tree oprnd0;
+ tree oprnd1;
+ tree left_offset = ssize_int (0);
+ tree right_offset = ssize_int (0);
+ tree left_misalign = ssize_int (0);
+ tree right_misalign = ssize_int (0);
+ tree left_step = ssize_int (0);
+ tree right_step = ssize_int (0);
+ enum tree_code code;
+ tree init, evolution;
+ tree left_aligned_to = NULL_TREE, right_aligned_to = NULL_TREE;
+
+ *step = NULL_TREE;
+ *misalign = NULL_TREE;
+ *aligned_to = NULL_TREE;
+ *initial_offset = NULL_TREE;
+
+ /* Strip conversions that don't narrow the mode. */
+ expr = strip_conversion (expr);
+ if (!expr)
+ return false;
+
+ /* Stop conditions:
+ 1. Constant. */
+ if (TREE_CODE (expr) == INTEGER_CST)
+ {
+ *initial_offset = fold_convert (ssizetype, expr);
+ *misalign = fold_convert (ssizetype, expr);
+ *step = ssize_int (0);
+ return true;
+ }
+
+ /* 2. Variable. Try to substitute with initial_condition of the corresponding
+ access_fn in the current loop. */
+ if (SSA_VAR_P (expr))
+ {
+ tree access_fn = analyze_scalar_evolution (loop, expr);
+
+ if (access_fn == chrec_dont_know)
+ /* No access_fn. */
+ return false;
+
+ init = initial_condition_in_loop_num (access_fn, loop->num);
+ if (init == expr && !expr_invariant_in_loop_p (loop, init))
+ /* Not enough information: may be not loop invariant.
+ E.g., for a[b[i]], we get a[D], where D=b[i]. EXPR is D, its
+ initial_condition is D, but it depends on i - loop's induction
+ variable. */
+ return false;
+
+ evolution = evolution_part_in_loop_num (access_fn, loop->num);
+ if (evolution && TREE_CODE (evolution) != INTEGER_CST)
+ /* Evolution is not constant. */
+ return false;
+
+ if (TREE_CODE (init) == INTEGER_CST)
+ *misalign = fold_convert (ssizetype, init);
+ else
+ /* Not constant, misalignment cannot be calculated. */
+ *misalign = NULL_TREE;
+
+ *initial_offset = fold_convert (ssizetype, init);
+
+ *step = evolution ? fold_convert (ssizetype, evolution) : ssize_int (0);
+ return true;
+ }
+
+ /* Recursive computation. */
+ if (!BINARY_CLASS_P (expr))
+ {
+ /* We expect to get binary expressions (PLUS/MINUS and MULT). */
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ {
+ fprintf (dump_file, "\nNot binary expression ");
+ print_generic_expr (dump_file, expr, TDF_SLIM);
+ fprintf (dump_file, "\n");
+ }
+ return false;
+ }
+ oprnd0 = TREE_OPERAND (expr, 0);
+ oprnd1 = TREE_OPERAND (expr, 1);
+
+ if (!analyze_offset_expr (oprnd0, loop, &left_offset, &left_misalign,
+ &left_aligned_to, &left_step)
+ || !analyze_offset_expr (oprnd1, loop, &right_offset, &right_misalign,
+ &right_aligned_to, &right_step))
+ return false;
+
+ /* The type of the operation: plus, minus or mult. */
+ code = TREE_CODE (expr);
+ switch (code)
+ {
+ case MULT_EXPR:
+ if (TREE_CODE (right_offset) != INTEGER_CST)
+ /* RIGHT_OFFSET can be not constant. For example, for arrays of variable
+ sized types.
+ FORNOW: We don't support such cases. */
+ return false;
+
+ /* Strip conversions that don't narrow the mode. */
+ left_offset = strip_conversion (left_offset);
+ if (!left_offset)
+ return false;
+ /* Misalignment computation. */
+ if (SSA_VAR_P (left_offset))
+ {
+ /* If the left side contains variables that can't be substituted with
+ constants, the misalignment is unknown. However, if the right side
+ is a multiple of some alignment, we know that the expression is
+ aligned to it. Therefore, we record such maximum possible value.
+ */
+ *misalign = NULL_TREE;
+ *aligned_to = ssize_int (highest_pow2_factor (right_offset));
+ }
+ else
+ {
+ /* The left operand was successfully substituted with constant. */
+ if (left_misalign)
+ {
+ /* In case of EXPR '(i * C1 + j) * C2', LEFT_MISALIGN is
+ NULL_TREE. */
+ *misalign = size_binop (code, left_misalign, right_misalign);
+ if (left_aligned_to && right_aligned_to)
+ *aligned_to = size_binop (MIN_EXPR, left_aligned_to,
+ right_aligned_to);
+ else
+ *aligned_to = left_aligned_to ?
+ left_aligned_to : right_aligned_to;
+ }
+ else
+ *misalign = NULL_TREE;
+ }
+
+ /* Step calculation. */
+ /* Multiply the step by the right operand. */
+ *step = size_binop (MULT_EXPR, left_step, right_offset);
+ break;
+
+ case PLUS_EXPR:
+ case MINUS_EXPR:
+ /* Combine the recursive calculations for step and misalignment. */
+ *step = size_binop (code, left_step, right_step);
+
+ /* Unknown alignment. */
+ if ((!left_misalign && !left_aligned_to)
+ || (!right_misalign && !right_aligned_to))
+ {
+ *misalign = NULL_TREE;
+ *aligned_to = NULL_TREE;
+ break;
+ }
+
+ if (left_misalign && right_misalign)
+ *misalign = size_binop (code, left_misalign, right_misalign);
+ else
+ *misalign = left_misalign ? left_misalign : right_misalign;
+
+ if (left_aligned_to && right_aligned_to)
+ *aligned_to = size_binop (MIN_EXPR, left_aligned_to, right_aligned_to);
+ else
+ *aligned_to = left_aligned_to ? left_aligned_to : right_aligned_to;
+
+ break;
+
+ default:
+ gcc_unreachable ();
+ }
+
+ /* Compute offset. */
+ *initial_offset = fold_convert (ssizetype,
+ fold_build2 (code, TREE_TYPE (left_offset),
+ left_offset,
+ right_offset));
+ return true;
+}
+
+/* Function address_analysis
+
+ Return the BASE of the address expression EXPR.
+ Also compute the OFFSET from BASE, MISALIGN and STEP.
+
+ Input:
+ EXPR - the address expression that is being analyzed
+ STMT - the statement that contains EXPR or its original memory reference
+ IS_READ - TRUE if STMT reads from EXPR, FALSE if writes to EXPR
+ DR - data_reference struct for the original memory reference
+
+ Output:
+ BASE (returned value) - the base of the data reference EXPR.
+ INITIAL_OFFSET - initial offset of EXPR from BASE (an expression)
+ MISALIGN - offset of EXPR from BASE in bytes (a constant) or NULL_TREE if the
+ computation is impossible
+ ALIGNED_TO - maximum alignment of EXPR or NULL_TREE if MISALIGN can be
+ calculated (doesn't depend on variables)
+ STEP - evolution of EXPR in the loop
+
+ If something unexpected is encountered (an unsupported form of data-ref),
+ then NULL_TREE is returned.
+ */
+
+static tree
+address_analysis (tree expr, tree stmt, bool is_read, struct data_reference *dr,
+ tree *offset, tree *misalign, tree *aligned_to, tree *step)
+{
+ tree oprnd0, oprnd1, base_address, offset_expr, base_addr0, base_addr1;
+ tree address_offset = ssize_int (0), address_misalign = ssize_int (0);
+ tree dummy, address_aligned_to = NULL_TREE;
+ struct ptr_info_def *dummy1;
+ subvar_t dummy2;
+
+ switch (TREE_CODE (expr))
+ {
+ case PLUS_EXPR:
+ case MINUS_EXPR:
+ /* EXPR is of form {base +/- offset} (or {offset +/- base}). */
+ oprnd0 = TREE_OPERAND (expr, 0);
+ oprnd1 = TREE_OPERAND (expr, 1);
+
+ STRIP_NOPS (oprnd0);
+ STRIP_NOPS (oprnd1);
+
+ /* Recursively try to find the base of the address contained in EXPR.
+ For offset, the returned base will be NULL. */
+ base_addr0 = address_analysis (oprnd0, stmt, is_read, dr, &address_offset,
+ &address_misalign, &address_aligned_to,
+ step);
+
+ base_addr1 = address_analysis (oprnd1, stmt, is_read, dr, &address_offset,
+ &address_misalign, &address_aligned_to,
+ step);
+
+ /* We support cases where only one of the operands contains an
+ address. */
+ if ((base_addr0 && base_addr1) || (!base_addr0 && !base_addr1))
+ {
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ {
+ fprintf (dump_file,
+ "\neither more than one address or no addresses in expr ");
+ print_generic_expr (dump_file, expr, TDF_SLIM);
+ fprintf (dump_file, "\n");
+ }
+ return NULL_TREE;
+ }
+
+ /* To revert STRIP_NOPS. */
+ oprnd0 = TREE_OPERAND (expr, 0);
+ oprnd1 = TREE_OPERAND (expr, 1);
+
+ offset_expr = base_addr0 ?
+ fold_convert (ssizetype, oprnd1) : fold_convert (ssizetype, oprnd0);
+
+ /* EXPR is of form {base +/- offset} (or {offset +/- base}). If offset is
+ a number, we can add it to the misalignment value calculated for base,
+ otherwise, misalignment is NULL. */
+ if (TREE_CODE (offset_expr) == INTEGER_CST && address_misalign)
+ {
+ *misalign = size_binop (TREE_CODE (expr), address_misalign,
+ offset_expr);
+ *aligned_to = address_aligned_to;
+ }
+ else
+ {
+ *misalign = NULL_TREE;
+ *aligned_to = NULL_TREE;
+ }
+
+ /* Combine offset (from EXPR {base + offset}) with the offset calculated
+ for base. */
+ *offset = size_binop (TREE_CODE (expr), address_offset, offset_expr);
+ return base_addr0 ? base_addr0 : base_addr1;
+
+ case ADDR_EXPR:
+ base_address = object_analysis (TREE_OPERAND (expr, 0), stmt, is_read,
+ &dr, offset, misalign, aligned_to, step,
+ &dummy, &dummy1, &dummy2);
+ return base_address;
+
+ case SSA_NAME:
+ if (!POINTER_TYPE_P (TREE_TYPE (expr)))
+ {
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ {
+ fprintf (dump_file, "\nnot pointer SSA_NAME ");
+ print_generic_expr (dump_file, expr, TDF_SLIM);
+ fprintf (dump_file, "\n");
+ }
+ return NULL_TREE;
+ }
+ *aligned_to = ssize_int (TYPE_ALIGN_UNIT (TREE_TYPE (TREE_TYPE (expr))));
+ *misalign = ssize_int (0);
+ *offset = ssize_int (0);
+ *step = ssize_int (0);
+ return expr;
+
+ default:
+ return NULL_TREE;
+ }
+}
+
+
+/* Function object_analysis
+
+ Create a data-reference structure DR for MEMREF.
+ Return the BASE of the data reference MEMREF if the analysis is possible.
+ Also compute the INITIAL_OFFSET from BASE, MISALIGN and STEP.
+ E.g., for EXPR a.b[i] + 4B, BASE is a, and OFFSET is the overall offset
+ 'a.b[i] + 4B' from a (can be an expression), MISALIGN is an OFFSET
+ instantiated with initial_conditions of access_functions of variables,
+ and STEP is the evolution of the DR_REF in this loop.
+
+ Function get_inner_reference is used for the above in case of ARRAY_REF and
+ COMPONENT_REF.
+
+ The structure of the function is as follows:
+ Part 1:
+ Case 1. For handled_component_p refs
+ 1.1 build data-reference structure for MEMREF
+ 1.2 call get_inner_reference
+ 1.2.1 analyze offset expr received from get_inner_reference
+ (fall through with BASE)
+ Case 2. For declarations
+ 2.1 set MEMTAG
+ Case 3. For INDIRECT_REFs
+ 3.1 build data-reference structure for MEMREF
+ 3.2 analyze evolution and initial condition of MEMREF
+ 3.3 set data-reference structure for MEMREF
+ 3.4 call address_analysis to analyze INIT of the access function
+ 3.5 extract memory tag
+
+ Part 2:
+ Combine the results of object and address analysis to calculate
+ INITIAL_OFFSET, STEP and misalignment info.
+
+ Input:
+ MEMREF - the memory reference that is being analyzed
+ STMT - the statement that contains MEMREF
+ IS_READ - TRUE if STMT reads from MEMREF, FALSE if writes to MEMREF
+
+ Output:
+ BASE_ADDRESS (returned value) - the base address of the data reference MEMREF
+ E.g, if MEMREF is a.b[k].c[i][j] the returned
+ base is &a.
+ DR - data_reference struct for MEMREF
+ INITIAL_OFFSET - initial offset of MEMREF from BASE (an expression)
+ MISALIGN - offset of MEMREF from BASE in bytes (a constant) modulo alignment of
+ ALIGNMENT or NULL_TREE if the computation is impossible
+ ALIGNED_TO - maximum alignment of EXPR or NULL_TREE if MISALIGN can be
+ calculated (doesn't depend on variables)
+ STEP - evolution of the DR_REF in the loop
+ MEMTAG - memory tag for aliasing purposes
+ PTR_INFO - NULL or points-to aliasing info from a pointer SSA_NAME
+ SUBVARS - Sub-variables of the variable
+
+ If the analysis of MEMREF evolution in the loop fails, NULL_TREE is returned,
+ but DR can be created anyway.
+
+*/
+
+static tree
+object_analysis (tree memref, tree stmt, bool is_read,
+ struct data_reference **dr, tree *offset, tree *misalign,
+ tree *aligned_to, tree *step, tree *memtag,
+ struct ptr_info_def **ptr_info, subvar_t *subvars)
+{
+ tree base = NULL_TREE, base_address = NULL_TREE;
+ tree object_offset = ssize_int (0), object_misalign = ssize_int (0);
+ tree object_step = ssize_int (0), address_step = ssize_int (0);
+ tree address_offset = ssize_int (0), address_misalign = ssize_int (0);
+ HOST_WIDE_INT pbitsize, pbitpos;
+ tree poffset, bit_pos_in_bytes;
+ enum machine_mode pmode;
+ int punsignedp, pvolatilep;
+ tree ptr_step = ssize_int (0), ptr_init = NULL_TREE;
+ struct loop *loop = loop_containing_stmt (stmt);
+ struct data_reference *ptr_dr = NULL;
+ tree object_aligned_to = NULL_TREE, address_aligned_to = NULL_TREE;
+
+ *ptr_info = NULL;
+
+ /* Part 1: */
+ /* Case 1. handled_component_p refs. */
+ if (handled_component_p (memref))
+ {
+ /* 1.1 build data-reference structure for MEMREF. */
+ /* TODO: handle COMPONENT_REFs. */
+ if (!(*dr))
+ {
+ if (TREE_CODE (memref) == ARRAY_REF)
+ *dr = analyze_array (stmt, memref, is_read);
+ else
+ {
+ /* FORNOW. */
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ {
+ fprintf (dump_file, "\ndata-ref of unsupported type ");
+ print_generic_expr (dump_file, memref, TDF_SLIM);
+ fprintf (dump_file, "\n");
+ }
+ return NULL_TREE;
+ }
+ }
+
+ /* 1.2 call get_inner_reference. */
+ /* Find the base and the offset from it. */
+ base = get_inner_reference (memref, &pbitsize, &pbitpos, &poffset,
+ &pmode, &punsignedp, &pvolatilep, false);
+ if (!base)
+ {
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ {
+ fprintf (dump_file, "\nfailed to get inner ref for ");
+ print_generic_expr (dump_file, memref, TDF_SLIM);
+ fprintf (dump_file, "\n");
+ }
+ return NULL_TREE;
+ }
+
+ /* 1.2.1 analyze offset expr received from get_inner_reference. */
+ if (poffset
+ && !analyze_offset_expr (poffset, loop, &object_offset,
+ &object_misalign, &object_aligned_to,
+ &object_step))
+ {
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ {
+ fprintf (dump_file, "\nfailed to compute offset or step for ");
+ print_generic_expr (dump_file, memref, TDF_SLIM);
+ fprintf (dump_file, "\n");
+ }
+ return NULL_TREE;
+ }
+
+ /* Add bit position to OFFSET and MISALIGN. */
+
+ bit_pos_in_bytes = ssize_int (pbitpos/BITS_PER_UNIT);
+ /* Check that there is no remainder in bits. */
+ if (pbitpos%BITS_PER_UNIT)
+ {
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ fprintf (dump_file, "\nbit offset alignment.\n");
+ return NULL_TREE;
+ }
+ object_offset = size_binop (PLUS_EXPR, bit_pos_in_bytes, object_offset);
+ if (object_misalign)
+ object_misalign = size_binop (PLUS_EXPR, object_misalign,
+ bit_pos_in_bytes);
+
+ memref = base; /* To continue analysis of BASE. */
+ /* fall through */
+ }
+
+ /* Part 1: Case 2. Declarations. */
+ if (DECL_P (memref))
+ {
+ /* We expect to get a decl only if we already have a DR. */
+ if (!(*dr))
+ {
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ {
+ fprintf (dump_file, "\nunhandled decl ");
+ print_generic_expr (dump_file, memref, TDF_SLIM);
+ fprintf (dump_file, "\n");
+ }
+ return NULL_TREE;
+ }
+
+ /* TODO: if during the analysis of INDIRECT_REF we get to an object, put
+ the object in BASE_OBJECT field if we can prove that this is O.K.,
+ i.e., the data-ref access is bounded by the bounds of the BASE_OBJECT.
+ (e.g., if the object is an array base 'a', where 'a[N]', we must prove
+ that every access with 'p' (the original INDIRECT_REF based on '&a')
+ in the loop is within the array boundaries - from a[0] to a[N-1]).
+ Otherwise, our alias analysis can be incorrect.
+ Even if an access function based on BASE_OBJECT can't be build, update
+ BASE_OBJECT field to enable us to prove that two data-refs are
+ different (without access function, distance analysis is impossible).
+ */
+ if (SSA_VAR_P (memref) && var_can_have_subvars (memref))
+ *subvars = get_subvars_for_var (memref);
+ base_address = build_fold_addr_expr (memref);
+ /* 2.1 set MEMTAG. */
+ *memtag = memref;
+ }
+
+ /* Part 1: Case 3. INDIRECT_REFs. */
+ else if (TREE_CODE (memref) == INDIRECT_REF)
+ {
+ tree ptr_ref = TREE_OPERAND (memref, 0);
+ if (TREE_CODE (ptr_ref) == SSA_NAME)
+ *ptr_info = SSA_NAME_PTR_INFO (ptr_ref);
+
+ /* 3.1 build data-reference structure for MEMREF. */
+ ptr_dr = analyze_indirect_ref (stmt, memref, is_read);
+ if (!ptr_dr)
+ {
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ {
+ fprintf (dump_file, "\nfailed to create dr for ");
+ print_generic_expr (dump_file, memref, TDF_SLIM);
+ fprintf (dump_file, "\n");
+ }
+ return NULL_TREE;
+ }
+
+ /* 3.2 analyze evolution and initial condition of MEMREF. */
+ ptr_step = DR_STEP (ptr_dr);
+ ptr_init = DR_BASE_ADDRESS (ptr_dr);
+ if (!ptr_init || !ptr_step || !POINTER_TYPE_P (TREE_TYPE (ptr_init)))
+ {
+ *dr = (*dr) ? *dr : ptr_dr;
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ {
+ fprintf (dump_file, "\nbad pointer access ");
+ print_generic_expr (dump_file, memref, TDF_SLIM);
+ fprintf (dump_file, "\n");
+ }
+ return NULL_TREE;
+ }
+
+ if (integer_zerop (ptr_step) && !(*dr))
+ {
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ fprintf (dump_file, "\nptr is loop invariant.\n");
+ *dr = ptr_dr;
+ return NULL_TREE;
+
+ /* If there exists DR for MEMREF, we are analyzing the base of
+ handled component (PTR_INIT), which not necessary has evolution in
+ the loop. */
+ }
+ object_step = size_binop (PLUS_EXPR, object_step, ptr_step);
+
+ /* 3.3 set data-reference structure for MEMREF. */
+ if (!*dr)
+ *dr = ptr_dr;
+
+ /* 3.4 call address_analysis to analyze INIT of the access
+ function. */
+ base_address = address_analysis (ptr_init, stmt, is_read, *dr,
+ &address_offset, &address_misalign,
+ &address_aligned_to, &address_step);
+ if (!base_address)
+ {
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ {
+ fprintf (dump_file, "\nfailed to analyze address ");
+ print_generic_expr (dump_file, ptr_init, TDF_SLIM);
+ fprintf (dump_file, "\n");
+ }
+ return NULL_TREE;
+ }
+
+ /* 3.5 extract memory tag. */
+ switch (TREE_CODE (base_address))
+ {
+ case SSA_NAME:
+ *memtag = get_var_ann (SSA_NAME_VAR (base_address))->type_mem_tag;
+ if (!(*memtag) && TREE_CODE (TREE_OPERAND (memref, 0)) == SSA_NAME)
+ *memtag = get_var_ann (
+ SSA_NAME_VAR (TREE_OPERAND (memref, 0)))->type_mem_tag;
+ break;
+ case ADDR_EXPR:
+ *memtag = TREE_OPERAND (base_address, 0);
+ break;
+ default:
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ {
+ fprintf (dump_file, "\nno memtag for ");
+ print_generic_expr (dump_file, memref, TDF_SLIM);
+ fprintf (dump_file, "\n");
+ }
+ *memtag = NULL_TREE;
+ break;
+ }
+ }
+
+ if (!base_address)
+ {
+ /* MEMREF cannot be analyzed. */
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ {
+ fprintf (dump_file, "\ndata-ref of unsupported type ");
+ print_generic_expr (dump_file, memref, TDF_SLIM);
+ fprintf (dump_file, "\n");
+ }
+ return NULL_TREE;
+ }
+
+ if (SSA_VAR_P (*memtag) && var_can_have_subvars (*memtag))
+ *subvars = get_subvars_for_var (*memtag);
+
+ /* Part 2: Combine the results of object and address analysis to calculate
+ INITIAL_OFFSET, STEP and misalignment info. */
+ *offset = size_binop (PLUS_EXPR, object_offset, address_offset);
+
+ if ((!object_misalign && !object_aligned_to)
+ || (!address_misalign && !address_aligned_to))
+ {
+ *misalign = NULL_TREE;
+ *aligned_to = NULL_TREE;
+ }
+ else
+ {
+ if (object_misalign && address_misalign)
+ *misalign = size_binop (PLUS_EXPR, object_misalign, address_misalign);
+ else
+ *misalign = object_misalign ? object_misalign : address_misalign;
+ if (object_aligned_to && address_aligned_to)
+ *aligned_to = size_binop (MIN_EXPR, object_aligned_to,
+ address_aligned_to);
+ else
+ *aligned_to = object_aligned_to ?
+ object_aligned_to : address_aligned_to;
+ }
+ *step = size_binop (PLUS_EXPR, object_step, address_step);
+
+ return base_address;
+}
+
+/* Function analyze_offset.
+
+ Extract INVARIANT and CONSTANT parts from OFFSET.
+
+*/
+static void
+analyze_offset (tree offset, tree *invariant, tree *constant)
+{
+ tree op0, op1, constant_0, constant_1, invariant_0, invariant_1;
+ enum tree_code code = TREE_CODE (offset);
+
+ *invariant = NULL_TREE;
+ *constant = NULL_TREE;
+
+ /* Not PLUS/MINUS expression - recursion stop condition. */
+ if (code != PLUS_EXPR && code != MINUS_EXPR)
+ {
+ if (TREE_CODE (offset) == INTEGER_CST)
+ *constant = offset;
+ else
+ *invariant = offset;
+ return;
+ }
+
+ op0 = TREE_OPERAND (offset, 0);
+ op1 = TREE_OPERAND (offset, 1);
+
+ /* Recursive call with the operands. */
+ analyze_offset (op0, &invariant_0, &constant_0);
+ analyze_offset (op1, &invariant_1, &constant_1);
+
+ /* Combine the results. */
+ *constant = constant_0 ? constant_0 : constant_1;
+ if (invariant_0 && invariant_1)
+ *invariant =
+ fold (build (code, TREE_TYPE (invariant_0), invariant_0, invariant_1));
+ else
+ *invariant = invariant_0 ? invariant_0 : invariant_1;
+}
+
+
+/* Function create_data_ref.
+
+ Create a data-reference structure for MEMREF. Set its DR_BASE_ADDRESS,
+ DR_OFFSET, DR_INIT, DR_STEP, DR_OFFSET_MISALIGNMENT, DR_ALIGNED_TO,
+ DR_MEMTAG, and DR_POINTSTO_INFO fields.
+
+ Input:
+ MEMREF - the memory reference that is being analyzed
+ STMT - the statement that contains MEMREF
+ IS_READ - TRUE if STMT reads from MEMREF, FALSE if writes to MEMREF
+
+ Output:
+ DR (returned value) - data_reference struct for MEMREF
+*/
+
+static struct data_reference *
+create_data_ref (tree memref, tree stmt, bool is_read)
+{
+ struct data_reference *dr = NULL;
+ tree base_address, offset, step, misalign, memtag;
+ struct loop *loop = loop_containing_stmt (stmt);
+ tree invariant = NULL_TREE, constant = NULL_TREE;
+ tree type_size, init_cond;
+ struct ptr_info_def *ptr_info;
+ subvar_t subvars = NULL;
+ tree aligned_to;
+
+ if (!memref)
+ return NULL;
+
+ base_address = object_analysis (memref, stmt, is_read, &dr, &offset,
+ &misalign, &aligned_to, &step, &memtag,
+ &ptr_info, &subvars);
+ if (!dr || !base_address)
+ {
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ {
+ fprintf (dump_file, "\ncreate_data_ref: failed to create a dr for ");
+ print_generic_expr (dump_file, memref, TDF_SLIM);
+ fprintf (dump_file, "\n");
+ }
+ return NULL;
+ }
+
+ DR_BASE_ADDRESS (dr) = base_address;
+ DR_OFFSET (dr) = offset;
+ DR_INIT (dr) = ssize_int (0);
+ DR_STEP (dr) = step;
+ DR_OFFSET_MISALIGNMENT (dr) = misalign;
+ DR_ALIGNED_TO (dr) = aligned_to;
+ DR_MEMTAG (dr) = memtag;
+ DR_PTR_INFO (dr) = ptr_info;
+ DR_SUBVARS (dr) = subvars;
+
+ type_size = fold_convert (ssizetype, TYPE_SIZE_UNIT (TREE_TYPE (DR_REF (dr))));
+
+ /* Change the access function for INIDIRECT_REFs, according to
+ DR_BASE_ADDRESS. Analyze OFFSET calculated in object_analysis. OFFSET is
+ an expression that can contain loop invariant expressions and constants.
+ We put the constant part in the initial condition of the access function
+ (for data dependence tests), and in DR_INIT of the data-ref. The loop
+ invariant part is put in DR_OFFSET.
+ The evolution part of the access function is STEP calculated in
+ object_analysis divided by the size of data type.
+ */
+ if (!DR_BASE_OBJECT (dr))
+ {
+ tree access_fn;
+ tree new_step;
+
+ /* Extract CONSTANT and INVARIANT from OFFSET, and put them in DR_INIT and
+ DR_OFFSET fields of DR. */
+ analyze_offset (offset, &invariant, &constant);
+ if (constant)
+ {
+ DR_INIT (dr) = fold_convert (ssizetype, constant);
+ init_cond = fold (build (TRUNC_DIV_EXPR, TREE_TYPE (constant),
+ constant, type_size));
+ }
+ else
+ DR_INIT (dr) = init_cond = ssize_int (0);;
+
+ if (invariant)
+ DR_OFFSET (dr) = invariant;
+ else
+ DR_OFFSET (dr) = ssize_int (0);
+
+ /* Update access function. */
+ access_fn = DR_ACCESS_FN (dr, 0);
+ new_step = size_binop (TRUNC_DIV_EXPR,
+ fold_convert (ssizetype, step), type_size);
+
+ access_fn = chrec_replace_initial_condition (access_fn, init_cond);
+ access_fn = reset_evolution_in_loop (loop->num, access_fn, new_step);
+
+ VEC_replace (tree, DR_ACCESS_FNS (dr), 0, access_fn);
+ }
+
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ {
+ struct ptr_info_def *pi = DR_PTR_INFO (dr);
+
+ fprintf (dump_file, "\nCreated dr for ");
+ print_generic_expr (dump_file, memref, TDF_SLIM);
+ fprintf (dump_file, "\n\tbase_address: ");
+ print_generic_expr (dump_file, DR_BASE_ADDRESS (dr), TDF_SLIM);
+ fprintf (dump_file, "\n\toffset from base address: ");
+ print_generic_expr (dump_file, DR_OFFSET (dr), TDF_SLIM);
+ fprintf (dump_file, "\n\tconstant offset from base address: ");
+ print_generic_expr (dump_file, DR_INIT (dr), TDF_SLIM);
+ fprintf (dump_file, "\n\tbase_object: ");
+ print_generic_expr (dump_file, DR_BASE_OBJECT (dr), TDF_SLIM);
+ fprintf (dump_file, "\n\tstep: ");
+ print_generic_expr (dump_file, DR_STEP (dr), TDF_SLIM);
+ fprintf (dump_file, "B\n\tmisalignment from base: ");
+ print_generic_expr (dump_file, DR_OFFSET_MISALIGNMENT (dr), TDF_SLIM);
+ if (DR_OFFSET_MISALIGNMENT (dr))
+ fprintf (dump_file, "B");
+ if (DR_ALIGNED_TO (dr))
+ {
+ fprintf (dump_file, "\n\taligned to: ");
+ print_generic_expr (dump_file, DR_ALIGNED_TO (dr), TDF_SLIM);
+ }
+ fprintf (dump_file, "\n\tmemtag: ");
+ print_generic_expr (dump_file, DR_MEMTAG (dr), TDF_SLIM);
+ fprintf (dump_file, "\n");
+ if (pi && pi->name_mem_tag)
+ {
+ fprintf (dump_file, "\n\tnametag: ");
+ print_generic_expr (dump_file, pi->name_mem_tag, TDF_SLIM);
+ fprintf (dump_file, "\n");
+ }
+ }
+ return dr;
+}
+
+
/* Returns true when all the functions of a tree_vec CHREC are the
same. */
@@ -692,43 +1936,58 @@ initialize_data_dependence_relation (struct data_reference *a,
{
struct data_dependence_relation *res;
bool differ_p;
+ unsigned int i;
res = xmalloc (sizeof (struct data_dependence_relation));
DDR_A (res) = a;
DDR_B (res) = b;
- if (a == NULL || b == NULL
- || DR_BASE_NAME (a) == NULL_TREE
- || DR_BASE_NAME (b) == NULL_TREE)
- DDR_ARE_DEPENDENT (res) = chrec_dont_know;
+ if (a == NULL || b == NULL)
+ {
+ DDR_ARE_DEPENDENT (res) = chrec_dont_know;
+ return res;
+ }
+
+ /* When A and B are arrays and their dimensions differ, we directly
+ initialize the relation to "there is no dependence": chrec_known. */
+ if (DR_BASE_OBJECT (a) && DR_BASE_OBJECT (b)
+ && DR_NUM_DIMENSIONS (a) != DR_NUM_DIMENSIONS (b))
+ {
+ DDR_ARE_DEPENDENT (res) = chrec_known;
+ return res;
+ }
- /* When the dimensions of A and B differ, we directly initialize
- the relation to "there is no dependence": chrec_known. */
- else if (DR_NUM_DIMENSIONS (a) != DR_NUM_DIMENSIONS (b)
- || (array_base_name_differ_p (a, b, &differ_p) && differ_p))
- DDR_ARE_DEPENDENT (res) = chrec_known;
-
- else
+ /* Compare the bases of the data-refs. */
+ if (!base_addr_differ_p (a, b, &differ_p))
{
- unsigned int i;
- DDR_AFFINE_P (res) = true;
- DDR_ARE_DEPENDENT (res) = NULL_TREE;
- DDR_SUBSCRIPTS_VECTOR_INIT (res, DR_NUM_DIMENSIONS (a));
- DDR_SIZE_VECT (res) = 0;
- DDR_DIST_VECT (res) = NULL;
- DDR_DIR_VECT (res) = NULL;
+ /* Can't determine whether the data-refs access the same memory
+ region. */
+ DDR_ARE_DEPENDENT (res) = chrec_dont_know;
+ return res;
+ }
+ if (differ_p)
+ {
+ DDR_ARE_DEPENDENT (res) = chrec_known;
+ return res;
+ }
+
+ DDR_AFFINE_P (res) = true;
+ DDR_ARE_DEPENDENT (res) = NULL_TREE;
+ DDR_SUBSCRIPTS_VECTOR_INIT (res, DR_NUM_DIMENSIONS (a));
+ DDR_SIZE_VECT (res) = 0;
+ DDR_DIST_VECT (res) = NULL;
+ DDR_DIR_VECT (res) = NULL;
- for (i = 0; i < DR_NUM_DIMENSIONS (a); i++)
- {
- struct subscript *subscript;
+ for (i = 0; i < DR_NUM_DIMENSIONS (a); i++)
+ {
+ struct subscript *subscript;
- subscript = xmalloc (sizeof (struct subscript));
- SUB_CONFLICTS_IN_A (subscript) = chrec_dont_know;
- SUB_CONFLICTS_IN_B (subscript) = chrec_dont_know;
- SUB_LAST_CONFLICT (subscript) = chrec_dont_know;
- SUB_DISTANCE (subscript) = chrec_dont_know;
- VARRAY_PUSH_GENERIC_PTR (DDR_SUBSCRIPTS (res), subscript);
- }
+ subscript = xmalloc (sizeof (struct subscript));
+ SUB_CONFLICTS_IN_A (subscript) = chrec_dont_know;
+ SUB_CONFLICTS_IN_B (subscript) = chrec_dont_know;
+ SUB_LAST_CONFLICT (subscript) = chrec_dont_know;
+ SUB_DISTANCE (subscript) = chrec_dont_know;
+ VARRAY_PUSH_GENERIC_PTR (DDR_SUBSCRIPTS (res), subscript);
}
return res;
@@ -1768,7 +3027,7 @@ subscript_dependence_tester (struct data_dependence_relation *ddr)
starting at FIRST_LOOP_DEPTH.
Return TRUE otherwise. */
-bool
+static bool
build_classic_dist_vector (struct data_dependence_relation *ddr,
int nb_loops, int first_loop_depth)
{
@@ -2123,7 +3382,7 @@ static bool
access_functions_are_affine_or_constant_p (struct data_reference *a)
{
unsigned int i;
- VEC(tree,heap) **fns = &DR_ACCESS_FNS (a);
+ VEC(tree,heap) **fns = DR_ACCESS_FNS_ADDR (a);
tree t;
for (i = 0; VEC_iterate (tree, *fns, i, t); i++)
@@ -2202,13 +3461,15 @@ DEF_VEC_P(ddr_p);
DEF_VEC_ALLOC_P(ddr_p,heap);
/* Compute a subset of the data dependence relation graph. Don't
- compute read-read relations, and avoid the computation of the
- opposite relation, i.e. when AB has been computed, don't compute BA.
+ compute read-read and self relations if
+ COMPUTE_SELF_AND_READ_READ_DEPENDENCES is FALSE, and avoid the computation
+ of the opposite relation, i.e. when AB has been computed, don't compute BA.
DATAREFS contains a list of data references, and the result is set
in DEPENDENCE_RELATIONS. */
static void
compute_all_dependences (varray_type datarefs,
+ bool compute_self_and_read_read_dependences,
VEC(ddr_p,heap) **dependence_relations)
{
unsigned int i, j, N;
@@ -2226,12 +3487,17 @@ compute_all_dependences (varray_type datarefs,
a = VARRAY_GENERIC_PTR (datarefs, i);
b = VARRAY_GENERIC_PTR (datarefs, j);
+ if (DR_IS_READ (a) && DR_IS_READ (b)
+ && !compute_self_and_read_read_dependences)
+ continue;
ddr = initialize_data_dependence_relation (a, b);
VEC_safe_push (ddr_p, heap, *dependence_relations, ddr);
compute_affine_dependence (ddr);
compute_subscript_distance (ddr);
}
+ if (!compute_self_and_read_read_dependences)
+ return;
/* Compute self dependence relation of each dataref to itself. */
@@ -2263,6 +3529,7 @@ find_data_references_in_loop (struct loop *loop, varray_type *datarefs)
basic_block bb, *bbs;
unsigned int i;
block_stmt_iterator bsi;
+ struct data_reference *dr;
bbs = get_loop_body (loop);
@@ -2289,33 +3556,55 @@ find_data_references_in_loop (struct loop *loop, varray_type *datarefs)
switch (TREE_CODE (stmt))
{
case MODIFY_EXPR:
- if (TREE_CODE (TREE_OPERAND (stmt, 0)) == ARRAY_REF)
- VARRAY_PUSH_GENERIC_PTR
- (*datarefs, analyze_array (stmt, TREE_OPERAND (stmt, 0),
- false));
-
- if (TREE_CODE (TREE_OPERAND (stmt, 1)) == ARRAY_REF)
- VARRAY_PUSH_GENERIC_PTR
- (*datarefs, analyze_array (stmt, TREE_OPERAND (stmt, 1),
- true));
+ {
+ bool one_inserted = false;
+ tree opnd0 = TREE_OPERAND (stmt, 0);
+ tree opnd1 = TREE_OPERAND (stmt, 1);
+
+ if (TREE_CODE (opnd0) == ARRAY_REF
+ || TREE_CODE (opnd0) == INDIRECT_REF)
+ {
+ dr = create_data_ref (opnd0, stmt, false);
+ if (dr)
+ {
+ VARRAY_PUSH_GENERIC_PTR (*datarefs, dr);
+ one_inserted = true;
+ }
+ }
+
+ if (TREE_CODE (opnd1) == ARRAY_REF
+ || TREE_CODE (opnd1) == INDIRECT_REF)
+ {
+ dr = create_data_ref (opnd1, stmt, true);
+ if (dr)
+ {
+ VARRAY_PUSH_GENERIC_PTR (*datarefs, dr);
+ one_inserted = true;
+ }
+ }
- if (TREE_CODE (TREE_OPERAND (stmt, 0)) != ARRAY_REF
- && TREE_CODE (TREE_OPERAND (stmt, 1)) != ARRAY_REF)
- goto insert_dont_know_node;
+ if (!one_inserted)
+ goto insert_dont_know_node;
- break;
+ break;
+ }
case CALL_EXPR:
{
tree args;
bool one_inserted = false;
- for (args = TREE_OPERAND (stmt, 1); args; args = TREE_CHAIN (args))
- if (TREE_CODE (TREE_VALUE (args)) == ARRAY_REF)
+ for (args = TREE_OPERAND (stmt, 1); args;
+ args = TREE_CHAIN (args))
+ if (TREE_CODE (TREE_VALUE (args)) == ARRAY_REF
+ || TREE_CODE (TREE_VALUE (args)) == INDIRECT_REF)
{
- VARRAY_PUSH_GENERIC_PTR
- (*datarefs, analyze_array (stmt, TREE_VALUE (args), true));
- one_inserted = true;
+ dr = create_data_ref (TREE_VALUE (args), stmt, true);
+ if (dr)
+ {
+ VARRAY_PUSH_GENERIC_PTR (*datarefs, dr);
+ one_inserted = true;
+ }
}
if (!one_inserted)
@@ -2332,9 +3621,18 @@ find_data_references_in_loop (struct loop *loop, varray_type *datarefs)
res = xmalloc (sizeof (struct data_reference));
DR_STMT (res) = NULL_TREE;
DR_REF (res) = NULL_TREE;
- DR_ACCESS_FNS (res) = NULL;
- DR_BASE_NAME (res) = NULL;
+ DR_BASE_OBJECT (res) = NULL;
+ DR_TYPE (res) = ARRAY_REF_TYPE;
+ DR_SET_ACCESS_FNS (res, NULL);
+ DR_BASE_OBJECT (res) = NULL;
DR_IS_READ (res) = false;
+ DR_BASE_ADDRESS (res) = NULL_TREE;
+ DR_OFFSET (res) = NULL_TREE;
+ DR_INIT (res) = NULL_TREE;
+ DR_STEP (res) = NULL_TREE;
+ DR_OFFSET_MISALIGNMENT (res) = NULL_TREE;
+ DR_MEMTAG (res) = NULL_TREE;
+ DR_PTR_INFO (res) = NULL;
VARRAY_PUSH_GENERIC_PTR (*datarefs, res);
free (bbs);
@@ -2362,17 +3660,25 @@ find_data_references_in_loop (struct loop *loop, varray_type *datarefs)
/* Given a loop nest LOOP, the following vectors are returned:
*DATAREFS is initialized to all the array elements contained in this loop,
- *DEPENDENCE_RELATIONS contains the relations between the data references. */
+ *DEPENDENCE_RELATIONS contains the relations between the data references.
+ Compute read-read and self relations if
+ COMPUTE_SELF_AND_READ_READ_DEPENDENCES is TRUE. */
void
-compute_data_dependences_for_loop (unsigned nb_loops,
- struct loop *loop,
+compute_data_dependences_for_loop (struct loop *loop,
+ bool compute_self_and_read_read_dependences,
varray_type *datarefs,
varray_type *dependence_relations)
{
- unsigned int i;
+ unsigned int i, nb_loops;
VEC(ddr_p,heap) *allrelations;
struct data_dependence_relation *ddr;
+ struct loop *loop_nest = loop;
+
+ while (loop_nest && loop_nest->outer && loop_nest->outer->outer)
+ loop_nest = loop_nest->outer;
+
+ nb_loops = loop_nest->level;
/* If one of the data references is not computable, give up without
spending time to compute other dependences. */
@@ -2390,14 +3696,15 @@ compute_data_dependences_for_loop (unsigned nb_loops,
}
allrelations = NULL;
- compute_all_dependences (*datarefs, &allrelations);
+ compute_all_dependences (*datarefs, compute_self_and_read_read_dependences,
+ &allrelations);
for (i = 0; VEC_iterate (ddr_p, allrelations, i, ddr); i++)
{
- if (build_classic_dist_vector (ddr, nb_loops, loop->depth))
+ if (build_classic_dist_vector (ddr, nb_loops, loop_nest->depth))
{
VARRAY_PUSH_GENERIC_PTR (*dependence_relations, ddr);
- build_classic_dir_vector (ddr, nb_loops, loop->depth);
+ build_classic_dir_vector (ddr, nb_loops, loop_nest->depth);
}
}
}
@@ -2438,7 +3745,7 @@ analyze_all_data_dependences (struct loops *loops)
"dependence_relations");
/* Compute DDs on the whole function. */
- compute_data_dependences_for_loop (loops->num, loops->parray[0],
+ compute_data_dependences_for_loop (loops->parray[0], false,
&datarefs, &dependence_relations);
if (dump_file)
@@ -2470,8 +3777,10 @@ analyze_all_data_dependences (struct loops *loops)
struct data_reference *b = DDR_B (ddr);
bool differ_p;
- if (DR_NUM_DIMENSIONS (a) != DR_NUM_DIMENSIONS (b)
- || (array_base_name_differ_p (a, b, &differ_p) && differ_p))
+ if ((DR_BASE_OBJECT (a) && DR_BASE_OBJECT (b)
+ && DR_NUM_DIMENSIONS (a) != DR_NUM_DIMENSIONS (b))
+ || (base_object_differ_p (a, b, &differ_p)
+ && differ_p))
nb_basename_differ++;
else
nb_bot_relations++;
@@ -2533,7 +3842,7 @@ free_data_refs (varray_type datarefs)
VARRAY_GENERIC_PTR (datarefs, i);
if (dr)
{
- VEC_free (tree, heap, DR_ACCESS_FNS (dr));
+ DR_FREE_ACCESS_FNS (dr);
free (dr);
}
}
diff --git a/gcc/tree-data-ref.h b/gcc/tree-data-ref.h
index 49e23e4..d0e6701 100644
--- a/gcc/tree-data-ref.h
+++ b/gcc/tree-data-ref.h
@@ -24,6 +24,50 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
#include "lambda.h"
+/** {base_address + offset + init} is the first location accessed by data-ref
+ in the loop, and step is the stride of data-ref in the loop in bytes;
+ e.g.:
+
+ Example 1 Example 2
+ data-ref a[j].b[i][j] a + x + 16B (a is int*)
+
+First location info:
+ base_address &a a
+ offset j_0*D_j + i_0*D_i + C_a x
+ init C_b 16
+ step D_j 4
+ access_fn NULL {16, +, 1}
+
+Base object info:
+ base_object a NULL
+ access_fn <access_fns of indexes of b> NULL
+
+ **/
+struct first_location_in_loop
+{
+ tree base_address;
+ tree offset;
+ tree init;
+ tree step;
+ /* Access function related to first location in the loop. */
+ VEC(tree,heap) *access_fns;
+
+};
+
+struct base_object_info
+{
+ /* The object. */
+ tree base_object;
+
+ /* A list of chrecs. Access functions related to BASE_OBJECT. */
+ VEC(tree,heap) *access_fns;
+};
+
+enum data_ref_type {
+ ARRAY_REF_TYPE,
+ POINTER_REF_TYPE
+};
+
struct data_reference
{
/* A pointer to the statement that contains this DR. */
@@ -32,27 +76,74 @@ struct data_reference
/* A pointer to the ARRAY_REF node. */
tree ref;
- /* The name of the array. */
- tree base_name;
-
- /* A list of chrecs. */
- VEC(tree,heap) *access_fns;
-
/* Auxiliary info specific to a pass. */
int aux;
/* True when the data reference is in RHS of a stmt. */
bool is_read;
+ /* First location accessed by the data-ref in the loop. */
+ struct first_location_in_loop first_location;
+
+ /* Base object related info. */
+ struct base_object_info object_info;
+
+ /* Aliasing information. This field represents the symbol that
+ should be aliased by a pointer holding the address of this data
+ reference. If the original data reference was a pointer
+ dereference, then this field contains the memory tag that should
+ be used by the new vector-pointer. */
+ tree memtag;
+ struct ptr_info_def *ptr_info;
+ subvar_t subvars;
+
+ /* Alignment information. */
+ /* The offset of the data-reference from its base in bytes. */
+ tree misalignment;
+ /* The maximum data-ref's alignment. */
+ tree aligned_to;
+
+ /* The type of the data-ref. */
+ enum data_ref_type type;
};
-#define DR_STMT(DR) DR->stmt
-#define DR_REF(DR) DR->ref
-#define DR_BASE_NAME(DR) DR->base_name
-#define DR_ACCESS_FNS(DR) DR->access_fns
-#define DR_ACCESS_FN(DR, I) VEC_index (tree, DR_ACCESS_FNS (DR), I)
-#define DR_NUM_DIMENSIONS(DR) VEC_length (tree, DR_ACCESS_FNS (DR))
-#define DR_IS_READ(DR) DR->is_read
+#define DR_STMT(DR) (DR)->stmt
+#define DR_REF(DR) (DR)->ref
+#define DR_BASE_OBJECT(DR) (DR)->object_info.base_object
+#define DR_TYPE(DR) (DR)->type
+#define DR_ACCESS_FNS(DR)\
+ (DR_TYPE(DR) == ARRAY_REF_TYPE ? \
+ (DR)->object_info.access_fns : (DR)->first_location.access_fns)
+#define DR_ACCESS_FN(DR, I) VEC_index (tree, DR_ACCESS_FNS (DR), I)
+#define DR_NUM_DIMENSIONS(DR) VEC_length (tree, DR_ACCESS_FNS (DR))
+#define DR_IS_READ(DR) (DR)->is_read
+#define DR_BASE_ADDRESS(DR) (DR)->first_location.base_address
+#define DR_OFFSET(DR) (DR)->first_location.offset
+#define DR_INIT(DR) (DR)->first_location.init
+#define DR_STEP(DR) (DR)->first_location.step
+#define DR_MEMTAG(DR) (DR)->memtag
+#define DR_ALIGNED_TO(DR) (DR)->aligned_to
+#define DR_OFFSET_MISALIGNMENT(DR) (DR)->misalignment
+#define DR_PTR_INFO(DR) (DR)->ptr_info
+#define DR_SUBVARS(DR) (DR)->subvars
+
+#define DR_ACCESS_FNS_ADDR(DR) \
+ (DR_TYPE(DR) == ARRAY_REF_TYPE ? \
+ &((DR)->object_info.access_fns) : &((DR)->first_location.access_fns))
+#define DR_SET_ACCESS_FNS(DR, ACC_FNS) \
+{ \
+ if (DR_TYPE(DR) == ARRAY_REF_TYPE) \
+ (DR)->object_info.access_fns = ACC_FNS; \
+ else \
+ (DR)->first_location.access_fns = ACC_FNS; \
+}
+#define DR_FREE_ACCESS_FNS(DR) \
+{ \
+ if (DR_TYPE(DR) == ARRAY_REF_TYPE) \
+ VEC_free (tree, heap, (DR)->object_info.access_fns); \
+ else \
+ VEC_free (tree, heap, (DR)->first_location.access_fns); \
+}
enum data_dependence_direction {
dir_positive,
@@ -156,10 +247,8 @@ extern struct data_dependence_relation *initialize_data_dependence_relation
(struct data_reference *, struct data_reference *);
extern void compute_affine_dependence (struct data_dependence_relation *);
extern void analyze_all_data_dependences (struct loops *);
-extern void compute_data_dependences_for_loop (unsigned, struct loop *,
+extern void compute_data_dependences_for_loop (struct loop *, bool,
varray_type *, varray_type *);
-extern struct data_reference * init_data_ref (tree, tree, tree, tree, bool);
-extern struct data_reference *analyze_array (tree, tree, bool);
extern void dump_subscript (FILE *, struct subscript *);
extern void dump_ddrs (FILE *, varray_type);
@@ -171,13 +260,10 @@ extern void dump_data_dependence_relation (FILE *,
extern void dump_data_dependence_relations (FILE *, varray_type);
extern void dump_data_dependence_direction (FILE *,
enum data_dependence_direction);
-extern bool array_base_name_differ_p (struct data_reference *,
- struct data_reference *, bool *);
extern void free_dependence_relation (struct data_dependence_relation *);
extern void free_dependence_relations (varray_type);
extern void free_data_refs (varray_type);
extern void compute_subscript_distance (struct data_dependence_relation *);
-extern bool build_classic_dist_vector (struct data_dependence_relation *, int, int);
diff --git a/gcc/tree-flow.h b/gcc/tree-flow.h
index d41a79c..4a0b4800 100644
--- a/gcc/tree-flow.h
+++ b/gcc/tree-flow.h
@@ -606,6 +606,7 @@ extern void debug_points_to_info (void);
extern void dump_points_to_info_for (FILE *, tree);
extern void debug_points_to_info_for (tree);
extern bool may_be_aliased (tree);
+extern bool is_aliased_with (tree, tree);
extern struct ptr_info_def *get_ptr_info (tree);
extern void add_type_alias (tree, tree);
extern void new_type_alias (tree, tree);
diff --git a/gcc/tree-loop-linear.c b/gcc/tree-loop-linear.c
index c93765a..0b13e2b 100644
--- a/gcc/tree-loop-linear.c
+++ b/gcc/tree-loop-linear.c
@@ -295,7 +295,7 @@ linear_transform_loops (struct loops *loops)
"dependence_relations");
- compute_data_dependences_for_loop (depth, loop_nest,
+ compute_data_dependences_for_loop (loop_nest, true,
&datarefs, &dependence_relations);
if (dump_file && (dump_flags & TDF_DETAILS))
{
diff --git a/gcc/tree-ssa-alias.c b/gcc/tree-ssa-alias.c
index 76d883a..62c741e 100644
--- a/gcc/tree-ssa-alias.c
+++ b/gcc/tree-ssa-alias.c
@@ -2219,6 +2219,40 @@ may_be_aliased (tree var)
}
+/* Given two symbols return TRUE if one is in the alias set of the other. */
+bool
+is_aliased_with (tree tag, tree sym)
+{
+ size_t i;
+ varray_type aliases;
+
+ if (var_ann (sym)->is_alias_tag)
+ {
+ aliases = var_ann (tag)->may_aliases;
+
+ if (aliases == NULL)
+ return false;
+
+ for (i = 0; i < VARRAY_ACTIVE_SIZE (aliases); i++)
+ if (VARRAY_TREE (aliases, i) == sym)
+ return true;
+ }
+ else
+ {
+ aliases = var_ann (sym)->may_aliases;
+
+ if (aliases == NULL)
+ return false;
+
+ for (i = 0; i < VARRAY_ACTIVE_SIZE (aliases); i++)
+ if (VARRAY_TREE (aliases, i) == tag)
+ return true;
+ }
+
+ return false;
+}
+
+
/* Add VAR to the list of may-aliases of PTR's type tag. If PTR
doesn't already have a type tag, create one. */
diff --git a/gcc/tree-vect-analyze.c b/gcc/tree-vect-analyze.c
index 267a6ff..45deb5c 100644
--- a/gcc/tree-vect-analyze.c
+++ b/gcc/tree-vect-analyze.c
@@ -57,234 +57,10 @@ static void vect_mark_relevant (VEC(tree,heap) **, tree, bool, bool);
static bool vect_stmt_relevant_p (tree, loop_vec_info, bool *, bool *);
static tree vect_get_loop_niters (struct loop *, tree *);
static bool vect_analyze_data_ref_dependence
- (struct data_reference *, struct data_reference *, loop_vec_info);
-static bool vect_compute_data_ref_alignment (struct data_reference *);
+ (struct data_dependence_relation *, loop_vec_info);
+static bool vect_compute_data_ref_alignment (struct data_reference *);
static bool vect_analyze_data_ref_access (struct data_reference *);
-static struct data_reference * vect_analyze_pointer_ref_access
- (tree, tree, bool, tree, tree *, tree *);
static bool vect_can_advance_ivs_p (loop_vec_info);
-static tree vect_get_ptr_offset (tree, tree, tree *);
-static bool vect_analyze_offset_expr (tree, struct loop *, tree, tree *,
- tree *, tree *);
-static bool vect_base_addr_differ_p (struct data_reference *,
- struct data_reference *drb, bool *);
-static tree vect_object_analysis (tree, tree, bool, tree,
- struct data_reference **, tree *, tree *,
- tree *, bool *, tree *, struct ptr_info_def **,
- subvar_t *);
-static tree vect_address_analysis (tree, tree, bool, tree,
- struct data_reference *, tree *, tree *,
- tree *, bool *);
-
-
-/* Function vect_get_ptr_offset
-
- Compute the OFFSET modulo vector-type alignment of pointer REF in bits. */
-
-static tree
-vect_get_ptr_offset (tree ref ATTRIBUTE_UNUSED,
- tree vectype ATTRIBUTE_UNUSED,
- tree *offset ATTRIBUTE_UNUSED)
-{
- /* TODO: Use alignment information. */
- return NULL_TREE;
-}
-
-
-/* Function vect_analyze_offset_expr
-
- Given an offset expression EXPR received from get_inner_reference, analyze
- it and create an expression for INITIAL_OFFSET by substituting the variables
- of EXPR with initial_condition of the corresponding access_fn in the loop.
- E.g.,
- for i
- for (j = 3; j < N; j++)
- a[j].b[i][j] = 0;
-
- For a[j].b[i][j], EXPR will be 'i * C_i + j * C_j + C'. 'i' cannot be
- substituted, since its access_fn in the inner loop is i. 'j' will be
- substituted with 3. An INITIAL_OFFSET will be 'i * C_i + C`', where
- C` = 3 * C_j + C.
-
- Compute MISALIGN (the misalignment of the data reference initial access from
- its base) if possible. Misalignment can be calculated only if all the
- variables can be substituted with constants, or if a variable is multiplied
- by a multiple of VECTYPE_ALIGNMENT. In the above example, since 'i' cannot
- be substituted, MISALIGN will be NULL_TREE in case that C_i is not a multiple
- of VECTYPE_ALIGNMENT, and C` otherwise. (We perform MISALIGN modulo
- VECTYPE_ALIGNMENT computation in the caller of this function).
-
- STEP is an evolution of the data reference in this loop in bytes.
- In the above example, STEP is C_j.
-
- Return FALSE, if the analysis fails, e.g., there is no access_fn for a
- variable. In this case, all the outputs (INITIAL_OFFSET, MISALIGN and STEP)
- are NULL_TREEs. Otherwise, return TRUE.
-
-*/
-
-static bool
-vect_analyze_offset_expr (tree expr,
- struct loop *loop,
- tree vectype_alignment,
- tree *initial_offset,
- tree *misalign,
- tree *step)
-{
- tree oprnd0;
- tree oprnd1;
- tree left_offset = ssize_int (0);
- tree right_offset = ssize_int (0);
- tree left_misalign = ssize_int (0);
- tree right_misalign = ssize_int (0);
- tree left_step = ssize_int (0);
- tree right_step = ssize_int (0);
- enum tree_code code;
- tree init, evolution;
-
- *step = NULL_TREE;
- *misalign = NULL_TREE;
- *initial_offset = NULL_TREE;
-
- /* Strip conversions that don't narrow the mode. */
- expr = vect_strip_conversion (expr);
- if (!expr)
- return false;
-
- /* Stop conditions:
- 1. Constant. */
- if (TREE_CODE (expr) == INTEGER_CST)
- {
- *initial_offset = fold_convert (ssizetype, expr);
- *misalign = fold_convert (ssizetype, expr);
- *step = ssize_int (0);
- return true;
- }
-
- /* 2. Variable. Try to substitute with initial_condition of the corresponding
- access_fn in the current loop. */
- if (SSA_VAR_P (expr))
- {
- tree access_fn = analyze_scalar_evolution (loop, expr);
-
- if (access_fn == chrec_dont_know)
- /* No access_fn. */
- return false;
-
- init = initial_condition_in_loop_num (access_fn, loop->num);
- if (init == expr && !expr_invariant_in_loop_p (loop, init))
- /* Not enough information: may be not loop invariant.
- E.g., for a[b[i]], we get a[D], where D=b[i]. EXPR is D, its
- initial_condition is D, but it depends on i - loop's induction
- variable. */
- return false;
-
- evolution = evolution_part_in_loop_num (access_fn, loop->num);
- if (evolution && TREE_CODE (evolution) != INTEGER_CST)
- /* Evolution is not constant. */
- return false;
-
- if (TREE_CODE (init) == INTEGER_CST)
- *misalign = fold_convert (ssizetype, init);
- else
- /* Not constant, misalignment cannot be calculated. */
- *misalign = NULL_TREE;
-
- *initial_offset = fold_convert (ssizetype, init);
-
- *step = evolution ? fold_convert (ssizetype, evolution) : ssize_int (0);
- return true;
- }
-
- /* Recursive computation. */
- if (!BINARY_CLASS_P (expr))
- {
- /* We expect to get binary expressions (PLUS/MINUS and MULT). */
- if (vect_print_dump_info (REPORT_DETAILS))
- {
- fprintf (vect_dump, "Not binary expression ");
- print_generic_expr (vect_dump, expr, TDF_SLIM);
- }
- return false;
- }
- oprnd0 = TREE_OPERAND (expr, 0);
- oprnd1 = TREE_OPERAND (expr, 1);
-
- if (!vect_analyze_offset_expr (oprnd0, loop, vectype_alignment, &left_offset,
- &left_misalign, &left_step)
- || !vect_analyze_offset_expr (oprnd1, loop, vectype_alignment,
- &right_offset, &right_misalign, &right_step))
- return false;
-
- /* The type of the operation: plus, minus or mult. */
- code = TREE_CODE (expr);
- switch (code)
- {
- case MULT_EXPR:
- if (TREE_CODE (right_offset) != INTEGER_CST)
- /* RIGHT_OFFSET can be not constant. For example, for arrays of variable
- sized types.
- FORNOW: We don't support such cases. */
- return false;
-
- /* Strip conversions that don't narrow the mode. */
- left_offset = vect_strip_conversion (left_offset);
- if (!left_offset)
- return false;
- /* Misalignment computation. */
- if (SSA_VAR_P (left_offset))
- {
- /* If the left side contains variables that can't be substituted with
- constants, we check if the right side is a multiple of ALIGNMENT.
- */
- if (integer_zerop (size_binop (TRUNC_MOD_EXPR, right_offset,
- fold_convert (ssizetype, vectype_alignment))))
- *misalign = ssize_int (0);
- else
- /* If the remainder is not zero or the right side isn't constant,
- we can't compute misalignment. */
- *misalign = NULL_TREE;
- }
- else
- {
- /* The left operand was successfully substituted with constant. */
- if (left_misalign)
- /* In case of EXPR '(i * C1 + j) * C2', LEFT_MISALIGN is
- NULL_TREE. */
- *misalign = size_binop (code, left_misalign, right_misalign);
- else
- *misalign = NULL_TREE;
- }
-
- /* Step calculation. */
- /* Multiply the step by the right operand. */
- *step = size_binop (MULT_EXPR, left_step, right_offset);
- break;
-
- case PLUS_EXPR:
- case MINUS_EXPR:
- /* Combine the recursive calculations for step and misalignment. */
- *step = size_binop (code, left_step, right_step);
-
- if (left_misalign && right_misalign)
- *misalign = size_binop (code, left_misalign, right_misalign);
- else
- *misalign = NULL_TREE;
-
- break;
-
- default:
- gcc_unreachable ();
- }
-
- /* Compute offset. */
- *initial_offset = fold_convert (ssizetype,
- fold_build2 (code, TREE_TYPE (left_offset),
- left_offset,
- right_offset));
- return true;
-}
-
/* Function vect_determine_vectorization_factor
@@ -780,86 +556,34 @@ vect_analyze_scalar_cycles (loop_vec_info loop_vinfo)
}
-/* Function vect_base_addr_differ_p.
-
- This is the simplest data dependence test: determines whether the
- data references A and B access the same array/region. Returns
- false when the property is not computable at compile time.
- Otherwise return true, and DIFFER_P will record the result. This
- utility will not be necessary when alias_sets_conflict_p will be
- less conservative. */
-
-static bool
-vect_base_addr_differ_p (struct data_reference *dra,
- struct data_reference *drb,
- bool *differ_p)
-{
- tree stmt_a = DR_STMT (dra);
- stmt_vec_info stmt_info_a = vinfo_for_stmt (stmt_a);
- tree stmt_b = DR_STMT (drb);
- stmt_vec_info stmt_info_b = vinfo_for_stmt (stmt_b);
- tree addr_a = STMT_VINFO_VECT_DR_BASE_ADDRESS (stmt_info_a);
- tree addr_b = STMT_VINFO_VECT_DR_BASE_ADDRESS (stmt_info_b);
- tree type_a = TREE_TYPE (addr_a);
- tree type_b = TREE_TYPE (addr_b);
- HOST_WIDE_INT alias_set_a, alias_set_b;
-
- gcc_assert (POINTER_TYPE_P (type_a) && POINTER_TYPE_P (type_b));
-
- /* Both references are ADDR_EXPR, i.e., we have the objects. */
- if (TREE_CODE (addr_a) == ADDR_EXPR && TREE_CODE (addr_b) == ADDR_EXPR)
- return array_base_name_differ_p (dra, drb, differ_p);
-
- alias_set_a = (TREE_CODE (addr_a) == ADDR_EXPR) ?
- get_alias_set (TREE_OPERAND (addr_a, 0)) : get_alias_set (addr_a);
- alias_set_b = (TREE_CODE (addr_b) == ADDR_EXPR) ?
- get_alias_set (TREE_OPERAND (addr_b, 0)) : get_alias_set (addr_b);
-
- if (!alias_sets_conflict_p (alias_set_a, alias_set_b))
- {
- *differ_p = true;
- return true;
- }
-
- /* An instruction writing through a restricted pointer is "independent" of any
- instruction reading or writing through a different pointer, in the same
- block/scope. */
- else if ((TYPE_RESTRICT (type_a) && !DR_IS_READ (dra))
- || (TYPE_RESTRICT (type_b) && !DR_IS_READ (drb)))
- {
- *differ_p = true;
- return true;
- }
- return false;
-}
-
-
/* Function vect_analyze_data_ref_dependence.
Return TRUE if there (might) exist a dependence between a memory-reference
DRA and a memory-reference DRB. */
-
+
static bool
-vect_analyze_data_ref_dependence (struct data_reference *dra,
- struct data_reference *drb,
- loop_vec_info loop_vinfo)
+vect_analyze_data_ref_dependence (struct data_dependence_relation *ddr,
+ loop_vec_info loop_vinfo)
{
- bool differ_p;
- struct data_dependence_relation *ddr;
struct loop *loop = LOOP_VINFO_LOOP (loop_vinfo);
int vectorization_factor = LOOP_VINFO_VECT_FACTOR (loop_vinfo);
int dist = 0;
unsigned int loop_depth = 0;
- struct loop *loop_nest = loop;
- stmt_vec_info stmtinfo_a = vinfo_for_stmt (DR_STMT (dra));
+ struct loop *loop_nest = loop;
+ struct data_reference *dra = DDR_A (ddr);
+ struct data_reference *drb = DDR_B (ddr);
+ stmt_vec_info stmtinfo_a = vinfo_for_stmt (DR_STMT (dra));
stmt_vec_info stmtinfo_b = vinfo_for_stmt (DR_STMT (drb));
+
+ if (DDR_ARE_DEPENDENT (ddr) == chrec_known)
+ return false;
- if (!vect_base_addr_differ_p (dra, drb, &differ_p))
+ if (DDR_ARE_DEPENDENT (ddr) == chrec_dont_know)
{
if (vect_print_dump_info (REPORT_UNVECTORIZED_LOOPS))
{
fprintf (vect_dump,
- "not vectorized: can't determine dependence between: ");
+ "not vectorized: can't determine dependence between ");
print_generic_expr (vect_dump, DR_REF (dra), TDF_SLIM);
fprintf (vect_dump, " and ");
print_generic_expr (vect_dump, DR_REF (drb), TDF_SLIM);
@@ -867,57 +591,28 @@ vect_analyze_data_ref_dependence (struct data_reference *dra,
return true;
}
- if (differ_p)
- return false;
-
- ddr = initialize_data_dependence_relation (dra, drb);
- compute_affine_dependence (ddr);
-
- if (DDR_ARE_DEPENDENT (ddr) == chrec_known)
- return false;
-
- if (DDR_ARE_DEPENDENT (ddr) == chrec_dont_know)
+ if (!DDR_DIST_VECT (ddr))
{
if (vect_print_dump_info (REPORT_UNVECTORIZED_LOOPS))
{
- fprintf (vect_dump,
- "not vectorized: can't determine dependence between ");
+ fprintf (vect_dump, "not vectorized: bad dist vector for ");
print_generic_expr (vect_dump, DR_REF (dra), TDF_SLIM);
fprintf (vect_dump, " and ");
print_generic_expr (vect_dump, DR_REF (drb), TDF_SLIM);
}
return true;
- }
+ }
/* Find loop depth. */
- while (loop_nest)
+ while (loop_nest && loop_nest->outer && loop_nest->outer->outer)
{
- if (loop_nest->outer && loop_nest->outer->outer)
- {
- loop_nest = loop_nest->outer;
- loop_depth++;
- }
- else
- break;
- }
-
- /* Compute distance vector. */
- compute_subscript_distance (ddr);
- build_classic_dist_vector (ddr, vect_loops_num, loop_nest->depth);
-
- if (!DDR_DIST_VECT (ddr))
- {
- if (vect_print_dump_info (REPORT_UNVECTORIZED_LOOPS))
- {
- fprintf (vect_dump, "not vectorized: bad dist vector for ");
- print_generic_expr (vect_dump, DR_REF (dra), TDF_SLIM);
- fprintf (vect_dump, " and ");
- print_generic_expr (vect_dump, DR_REF (drb), TDF_SLIM);
- }
- return true;
+ loop_nest = loop_nest->outer;
+ loop_depth++;
}
-
+
dist = DDR_DIST_VECT (ddr)[loop_depth];
+ if (vect_print_dump_info (REPORT_DR_DETAILS))
+ fprintf (vect_dump, "dependence distance = %d.",dist);
/* Same loop iteration. */
if (dist % vectorization_factor == 0)
@@ -926,76 +621,59 @@ vect_analyze_data_ref_dependence (struct data_reference *dra,
VEC_safe_push (dr_p, heap, STMT_VINFO_SAME_ALIGN_REFS (stmtinfo_a), drb);
VEC_safe_push (dr_p, heap, STMT_VINFO_SAME_ALIGN_REFS (stmtinfo_b), dra);
if (vect_print_dump_info (REPORT_ALIGNMENT))
- fprintf (vect_dump, "accesses have the same alignment.");
+ fprintf (vect_dump, "accesses have the same alignment.");
+ if (vect_print_dump_info (REPORT_DR_DETAILS))
+ {
+ fprintf (vect_dump, "dependence distance modulo vf == 0 between ");
+ print_generic_expr (vect_dump, DR_REF (dra), TDF_SLIM);
+ fprintf (vect_dump, " and ");
+ print_generic_expr (vect_dump, DR_REF (drb), TDF_SLIM);
+ }
return false;
- }
+ }
- if (dist >= vectorization_factor)
- /* Dependence distance does not create dependence, as far as vectorization
- is concerned, in this case. */
- return false;
-
+ if (abs (dist) >= vectorization_factor)
+ {
+ /* Dependence distance does not create dependence, as far as vectorization
+ is concerned, in this case. */
+ if (vect_print_dump_info (REPORT_DR_DETAILS))
+ fprintf (vect_dump, "dependence distance >= VF.");
+ return false;
+ }
+
if (vect_print_dump_info (REPORT_UNVECTORIZED_LOOPS))
{
fprintf (vect_dump,
- "not vectorized: possible dependence between data-refs ");
+ "not vectorized: possible dependence between data-refs ");
print_generic_expr (vect_dump, DR_REF (dra), TDF_SLIM);
fprintf (vect_dump, " and ");
print_generic_expr (vect_dump, DR_REF (drb), TDF_SLIM);
}
-
+
return true;
}
/* Function vect_analyze_data_ref_dependences.
-
+
Examine all the data references in the loop, and make sure there do not
exist any data dependences between them. */
-
+
static bool
vect_analyze_data_ref_dependences (loop_vec_info loop_vinfo)
{
- unsigned int i, j;
- varray_type loop_write_refs = LOOP_VINFO_DATAREF_WRITES (loop_vinfo);
- varray_type loop_read_refs = LOOP_VINFO_DATAREF_READS (loop_vinfo);
-
- /* Examine store-store (output) dependences. */
+ unsigned int i;
+ varray_type ddrs = LOOP_VINFO_DDRS (loop_vinfo);
- if (vect_print_dump_info (REPORT_DETAILS))
+ if (vect_print_dump_info (REPORT_DETAILS))
fprintf (vect_dump, "=== vect_analyze_dependences ===");
-
- if (vect_print_dump_info (REPORT_DETAILS))
- fprintf (vect_dump, "compare all store-store pairs.");
-
- for (i = 0; i < VARRAY_ACTIVE_SIZE (loop_write_refs); i++)
- {
- for (j = i + 1; j < VARRAY_ACTIVE_SIZE (loop_write_refs); j++)
- {
- struct data_reference *dra =
- VARRAY_GENERIC_PTR (loop_write_refs, i);
- struct data_reference *drb =
- VARRAY_GENERIC_PTR (loop_write_refs, j);
- if (vect_analyze_data_ref_dependence (dra, drb, loop_vinfo))
- return false;
- }
- }
-
- /* Examine load-store (true/anti) dependences. */
-
- if (vect_print_dump_info (REPORT_DETAILS))
- fprintf (vect_dump, "compare all load-store pairs.");
-
- for (i = 0; i < VARRAY_ACTIVE_SIZE (loop_read_refs); i++)
+
+ for (i = 0; i < VARRAY_ACTIVE_SIZE (ddrs); i++)
{
- for (j = 0; j < VARRAY_ACTIVE_SIZE (loop_write_refs); j++)
- {
- struct data_reference *dra = VARRAY_GENERIC_PTR (loop_read_refs, i);
- struct data_reference *drb =
- VARRAY_GENERIC_PTR (loop_write_refs, j);
- if (vect_analyze_data_ref_dependence (dra, drb, loop_vinfo))
- return false;
- }
+ struct data_dependence_relation *ddr = VARRAY_GENERIC_PTR (ddrs, i);
+
+ if (vect_analyze_data_ref_dependence (ddr, loop_vinfo))
+ return false;
}
return true;
@@ -1021,9 +699,10 @@ vect_compute_data_ref_alignment (struct data_reference *dr)
stmt_vec_info stmt_info = vinfo_for_stmt (stmt);
tree ref = DR_REF (dr);
tree vectype;
- tree base, alignment;
- bool base_aligned_p;
+ tree base, base_addr;
+ bool base_aligned;
tree misalign;
+ tree aligned_to, alignment;
if (vect_print_dump_info (REPORT_DETAILS))
fprintf (vect_dump, "vect_compute_data_ref_alignment:");
@@ -1031,12 +710,15 @@ vect_compute_data_ref_alignment (struct data_reference *dr)
/* Initialize misalignment to unknown. */
DR_MISALIGNMENT (dr) = -1;
- misalign = STMT_VINFO_VECT_MISALIGNMENT (stmt_info);
- base_aligned_p = STMT_VINFO_VECT_BASE_ALIGNED_P (stmt_info);
- base = build_fold_indirect_ref (STMT_VINFO_VECT_DR_BASE_ADDRESS (stmt_info));
+ misalign = DR_OFFSET_MISALIGNMENT (dr);
+ aligned_to = DR_ALIGNED_TO (dr);
+ base_addr = DR_BASE_ADDRESS (dr);
+ base = build_fold_indirect_ref (base_addr);
vectype = STMT_VINFO_VECTYPE (stmt_info);
+ alignment = ssize_int (TYPE_ALIGN (vectype)/BITS_PER_UNIT);
- if (!misalign)
+ if ((aligned_to && tree_int_cst_compare (aligned_to, alignment) < 0)
+ || !misalign)
{
if (vect_print_dump_info (REPORT_DETAILS))
{
@@ -1046,7 +728,18 @@ vect_compute_data_ref_alignment (struct data_reference *dr)
return true;
}
- if (!base_aligned_p)
+ if ((DECL_P (base)
+ && tree_int_cst_compare (ssize_int (DECL_ALIGN_UNIT (base)),
+ alignment) >= 0)
+ || (TREE_CODE (base_addr) == SSA_NAME
+ && tree_int_cst_compare (ssize_int (TYPE_ALIGN_UNIT (TREE_TYPE (
+ TREE_TYPE (base_addr)))),
+ alignment) >= 0))
+ base_aligned = true;
+ else
+ base_aligned = false;
+
+ if (!base_aligned)
{
if (!vect_can_force_dr_alignment_p (base, TYPE_ALIGN (vectype)))
{
@@ -1068,15 +761,13 @@ vect_compute_data_ref_alignment (struct data_reference *dr)
}
/* At this point we assume that the base is aligned. */
- gcc_assert (base_aligned_p
+ gcc_assert (base_aligned
|| (TREE_CODE (base) == VAR_DECL
&& DECL_ALIGN (base) >= TYPE_ALIGN (vectype)));
- /* Alignment required, in bytes: */
- alignment = ssize_int (TYPE_ALIGN (vectype)/BITS_PER_UNIT);
-
/* Modulo alignment. */
misalign = size_binop (TRUNC_MOD_EXPR, misalign, alignment);
+
if (tree_int_cst_sgn (misalign) < 0)
{
/* Negative misalignment value. */
@@ -1088,7 +779,10 @@ vect_compute_data_ref_alignment (struct data_reference *dr)
DR_MISALIGNMENT (dr) = tree_low_cst (misalign, 1);
if (vect_print_dump_info (REPORT_DETAILS))
- fprintf (vect_dump, "misalign = %d bytes", DR_MISALIGNMENT (dr));
+ {
+ fprintf (vect_dump, "misalign = %d bytes of ref ", DR_MISALIGNMENT (dr));
+ print_generic_expr (vect_dump, ref, TDF_SLIM);
+ }
return true;
}
@@ -1106,20 +800,12 @@ vect_compute_data_ref_alignment (struct data_reference *dr)
static bool
vect_compute_data_refs_alignment (loop_vec_info loop_vinfo)
{
- varray_type loop_write_datarefs = LOOP_VINFO_DATAREF_WRITES (loop_vinfo);
- varray_type loop_read_datarefs = LOOP_VINFO_DATAREF_READS (loop_vinfo);
+ varray_type datarefs = LOOP_VINFO_DATAREFS (loop_vinfo);
unsigned int i;
- for (i = 0; i < VARRAY_ACTIVE_SIZE (loop_write_datarefs); i++)
- {
- struct data_reference *dr = VARRAY_GENERIC_PTR (loop_write_datarefs, i);
- if (!vect_compute_data_ref_alignment (dr))
- return false;
- }
-
- for (i = 0; i < VARRAY_ACTIVE_SIZE (loop_read_datarefs); i++)
+ for (i = 0; i < VARRAY_ACTIVE_SIZE (datarefs); i++)
{
- struct data_reference *dr = VARRAY_GENERIC_PTR (loop_read_datarefs, i);
+ struct data_reference *dr = VARRAY_GENERIC_PTR (datarefs, i);
if (!vect_compute_data_ref_alignment (dr))
return false;
}
@@ -1141,13 +827,13 @@ vect_compute_data_refs_alignment (loop_vec_info loop_vinfo)
static void
vect_enhance_data_refs_alignment (loop_vec_info loop_vinfo)
{
- varray_type loop_read_datarefs = LOOP_VINFO_DATAREF_READS (loop_vinfo);
- varray_type loop_write_datarefs = LOOP_VINFO_DATAREF_WRITES (loop_vinfo);
+ varray_type loop_datarefs = LOOP_VINFO_DATAREFS (loop_vinfo);
varray_type datarefs;
VEC(dr_p,heap) *same_align_drs;
struct data_reference *dr0 = NULL;
struct data_reference *dr;
unsigned int i, j;
+ bool check_loads;
/*
This pass will require a cost model to guide it whether to apply peeling
@@ -1248,10 +934,10 @@ vect_enhance_data_refs_alignment (loop_vec_info loop_vinfo)
TODO: Use a better cost model. */
- for (i = 0; i < VARRAY_ACTIVE_SIZE (loop_write_datarefs); i++)
+ for (i = 0; i < VARRAY_ACTIVE_SIZE (loop_datarefs); i++)
{
- dr0 = VARRAY_GENERIC_PTR (loop_write_datarefs, i);
- if (!aligned_access_p (dr0))
+ dr0 = VARRAY_GENERIC_PTR (loop_datarefs, i);
+ if (!DR_IS_READ (dr0) && !aligned_access_p (dr0))
{
LOOP_VINFO_UNALIGNED_DR (loop_vinfo) = dr0;
LOOP_PEELING_FOR_ALIGNMENT (loop_vinfo) = DR_MISALIGNMENT (dr0);
@@ -1285,14 +971,15 @@ vect_enhance_data_refs_alignment (loop_vec_info loop_vinfo)
npeel = LOOP_VINFO_VECT_FACTOR (loop_vinfo) - mis;
}
- datarefs = loop_write_datarefs;
+ datarefs = loop_datarefs;
+ check_loads = false;
for (j = 0; j < 2; j++)
{
for (i = 0; i < VARRAY_ACTIVE_SIZE (datarefs); i++)
{
struct data_reference *dr = VARRAY_GENERIC_PTR (datarefs, i);
- if (dr == dr0)
+ if (dr == dr0 || (!check_loads && DR_IS_READ (dr)))
continue;
if (known_alignment_for_access_p (dr)
&& DR_MISALIGNMENT (dr) == DR_MISALIGNMENT (dr0))
@@ -1309,7 +996,7 @@ vect_enhance_data_refs_alignment (loop_vec_info loop_vinfo)
else
DR_MISALIGNMENT (dr) = -1;
}
- datarefs = loop_read_datarefs;
+ check_loads = true;
}
same_align_drs =
@@ -1334,8 +1021,7 @@ vect_enhance_data_refs_alignment (loop_vec_info loop_vinfo)
static bool
vect_analyze_data_refs_alignment (loop_vec_info loop_vinfo)
{
- varray_type loop_read_datarefs = LOOP_VINFO_DATAREF_READS (loop_vinfo);
- varray_type loop_write_datarefs = LOOP_VINFO_DATAREF_WRITES (loop_vinfo);
+ varray_type datarefs = LOOP_VINFO_DATAREFS (loop_vinfo);
enum dr_alignment_support supportable_dr_alignment;
unsigned int i;
@@ -1364,29 +1050,19 @@ vect_analyze_data_refs_alignment (loop_vec_info loop_vinfo)
/* Finally, check that all the data references in the loop can be
handled with respect to their alignment. */
- for (i = 0; i < VARRAY_ACTIVE_SIZE (loop_read_datarefs); i++)
- {
- struct data_reference *dr = VARRAY_GENERIC_PTR (loop_read_datarefs, i);
- supportable_dr_alignment = vect_supportable_dr_alignment (dr);
- if (!supportable_dr_alignment)
- {
- if (vect_print_dump_info (REPORT_UNVECTORIZED_LOOPS))
- fprintf (vect_dump, "not vectorized: unsupported unaligned load.");
- return false;
- }
- if (supportable_dr_alignment != dr_aligned
- && (vect_print_dump_info (REPORT_ALIGNMENT)))
- fprintf (vect_dump, "Vectorizing an unaligned access.");
- }
- for (i = 0; i < VARRAY_ACTIVE_SIZE (loop_write_datarefs); i++)
+ for (i = 0; i < VARRAY_ACTIVE_SIZE (datarefs); i++)
{
- struct data_reference *dr = VARRAY_GENERIC_PTR (loop_write_datarefs, i);
+ struct data_reference *dr = VARRAY_GENERIC_PTR (datarefs, i);
supportable_dr_alignment = vect_supportable_dr_alignment (dr);
if (!supportable_dr_alignment)
{
- if (vect_print_dump_info (REPORT_UNVECTORIZED_LOOPS))
- fprintf (vect_dump, "not vectorized: unsupported unaligned store.");
- return false;
+ if (DR_IS_READ (dr))
+ fprintf (vect_dump,
+ "not vectorized: unsupported unaligned load.");
+ else
+ fprintf (vect_dump,
+ "not vectorized: unsupported unaligned store.");
+ return false;
}
if (supportable_dr_alignment != dr_aligned
&& (vect_print_dump_info (REPORT_ALIGNMENT)))
@@ -1395,7 +1071,6 @@ vect_analyze_data_refs_alignment (loop_vec_info loop_vinfo)
if (LOOP_VINFO_UNALIGNED_DR (loop_vinfo)
&& vect_print_dump_info (REPORT_ALIGNMENT))
fprintf (vect_dump, "Alignment of access forced using peeling.");
-
return true;
}
@@ -1408,9 +1083,7 @@ vect_analyze_data_refs_alignment (loop_vec_info loop_vinfo)
static bool
vect_analyze_data_ref_access (struct data_reference *dr)
{
- tree stmt = DR_STMT (dr);
- stmt_vec_info stmt_info = vinfo_for_stmt (stmt);
- tree step = STMT_VINFO_VECT_STEP (stmt_info);
+ tree step = DR_STEP (dr);
tree scalar_type = TREE_TYPE (DR_REF (dr));
if (!step || tree_int_cst_compare (step, TYPE_SIZE_UNIT (scalar_type)))
@@ -1436,29 +1109,15 @@ static bool
vect_analyze_data_ref_accesses (loop_vec_info loop_vinfo)
{
unsigned int i;
- varray_type loop_write_datarefs = LOOP_VINFO_DATAREF_WRITES (loop_vinfo);
- varray_type loop_read_datarefs = LOOP_VINFO_DATAREF_READS (loop_vinfo);
+ varray_type datarefs = LOOP_VINFO_DATAREFS (loop_vinfo);
if (vect_print_dump_info (REPORT_DETAILS))
fprintf (vect_dump, "=== vect_analyze_data_ref_accesses ===");
- for (i = 0; i < VARRAY_ACTIVE_SIZE (loop_write_datarefs); i++)
+ for (i = 0; i < VARRAY_ACTIVE_SIZE (datarefs); i++)
{
- struct data_reference *dr = VARRAY_GENERIC_PTR (loop_write_datarefs, i);
- bool ok = vect_analyze_data_ref_access (dr);
- if (!ok)
- {
- if (vect_print_dump_info (REPORT_UNVECTORIZED_LOOPS))
- fprintf (vect_dump, "not vectorized: complicated access pattern.");
- return false;
- }
- }
-
- for (i = 0; i < VARRAY_ACTIVE_SIZE (loop_read_datarefs); i++)
- {
- struct data_reference *dr = VARRAY_GENERIC_PTR (loop_read_datarefs, i);
- bool ok = vect_analyze_data_ref_access (dr);
- if (!ok)
+ struct data_reference *dr = VARRAY_GENERIC_PTR (datarefs, i);
+ if (!vect_analyze_data_ref_access (dr))
{
if (vect_print_dump_info (REPORT_UNVECTORIZED_LOOPS))
fprintf (vect_dump, "not vectorized: complicated access pattern.");
@@ -1470,640 +1129,106 @@ vect_analyze_data_ref_accesses (loop_vec_info loop_vinfo)
}
-/* Function vect_analyze_pointer_ref_access.
-
- Input:
- STMT - a stmt that contains a data-ref.
- MEMREF - a data-ref in STMT, which is an INDIRECT_REF.
- ACCESS_FN - the access function of MEMREF.
-
- Output:
- If the data-ref access is vectorizable, return a data_reference structure
- that represents it (DR). Otherwise - return NULL.
- STEP - the stride of MEMREF in the loop.
- INIT - the initial condition of MEMREF in the loop.
-*/
-
-static struct data_reference *
-vect_analyze_pointer_ref_access (tree memref, tree stmt, bool is_read,
- tree access_fn, tree *ptr_init, tree *ptr_step)
-{
- stmt_vec_info stmt_info = vinfo_for_stmt (stmt);
- loop_vec_info loop_vinfo = STMT_VINFO_LOOP_VINFO (stmt_info);
- struct loop *loop = LOOP_VINFO_LOOP (loop_vinfo);
- tree step, init;
- tree reftype, innertype;
- tree indx_access_fn;
- int loopnum = loop->num;
- struct data_reference *dr;
-
- if (!vect_is_simple_iv_evolution (loopnum, access_fn, &init, &step))
- {
- if (vect_print_dump_info (REPORT_UNVECTORIZED_LOOPS))
- fprintf (vect_dump, "not vectorized: pointer access is not simple.");
- return NULL;
- }
-
- STRIP_NOPS (init);
-
- if (!expr_invariant_in_loop_p (loop, init))
- {
- if (vect_print_dump_info (REPORT_UNVECTORIZED_LOOPS))
- fprintf (vect_dump,
- "not vectorized: initial condition is not loop invariant.");
- return NULL;
- }
-
- if (TREE_CODE (step) != INTEGER_CST)
- {
- if (vect_print_dump_info (REPORT_UNVECTORIZED_LOOPS))
- fprintf (vect_dump,
- "not vectorized: non constant step for pointer access.");
- return NULL;
- }
-
- reftype = TREE_TYPE (TREE_OPERAND (memref, 0));
- if (!POINTER_TYPE_P (reftype))
- {
- if (vect_print_dump_info (REPORT_UNVECTORIZED_LOOPS))
- fprintf (vect_dump, "not vectorized: unexpected pointer access form.");
- return NULL;
- }
-
- if (!POINTER_TYPE_P (TREE_TYPE (init)))
- {
- if (vect_print_dump_info (REPORT_UNVECTORIZED_LOOPS))
- fprintf (vect_dump, "not vectorized: unexpected pointer access form.");
- return NULL;
- }
-
- *ptr_step = fold_convert (ssizetype, step);
- innertype = TREE_TYPE (reftype);
- if (!COMPLETE_TYPE_P (innertype))
- {
- if (vect_print_dump_info (REPORT_UNVECTORIZED_LOOPS))
- fprintf (vect_dump, "not vectorized: pointer to incomplete type.");
- return NULL;
- }
-
- /* Check that STEP is a multiple of type size. */
- if (!integer_zerop (size_binop (TRUNC_MOD_EXPR, *ptr_step,
- fold_convert (ssizetype, TYPE_SIZE_UNIT (innertype)))))
- {
- if (vect_print_dump_info (REPORT_UNVECTORIZED_LOOPS))
- fprintf (vect_dump, "not vectorized: non consecutive access.");
- return NULL;
- }
-
- indx_access_fn =
- build_polynomial_chrec (loopnum, integer_zero_node, integer_one_node);
- if (vect_print_dump_info (REPORT_DETAILS))
- {
- fprintf (vect_dump, "Access function of ptr indx: ");
- print_generic_expr (vect_dump, indx_access_fn, TDF_SLIM);
- }
- dr = init_data_ref (stmt, memref, NULL_TREE, indx_access_fn, is_read);
- *ptr_init = init;
- return dr;
-}
-
-
-/* Function vect_address_analysis
-
- Return the BASE of the address expression EXPR.
- Also compute the INITIAL_OFFSET from BASE, MISALIGN and STEP.
-
- Input:
- EXPR - the address expression that is being analyzed
- STMT - the statement that contains EXPR or its original memory reference
- IS_READ - TRUE if STMT reads from EXPR, FALSE if writes to EXPR
- VECTYPE - the type that defines the alignment (i.e, we compute
- alignment relative to TYPE_ALIGN(VECTYPE))
- DR - data_reference struct for the original memory reference
-
- Output:
- BASE (returned value) - the base of the data reference EXPR.
- INITIAL_OFFSET - initial offset of EXPR from BASE (an expression)
- MISALIGN - offset of EXPR from BASE in bytes (a constant) or NULL_TREE if the
- computation is impossible
- STEP - evolution of EXPR in the loop
- BASE_ALIGNED - indicates if BASE is aligned
-
- If something unexpected is encountered (an unsupported form of data-ref),
- then NULL_TREE is returned.
- */
-
-static tree
-vect_address_analysis (tree expr, tree stmt, bool is_read, tree vectype,
- struct data_reference *dr, tree *offset, tree *misalign,
- tree *step, bool *base_aligned)
-{
- tree oprnd0, oprnd1, base_address, offset_expr, base_addr0, base_addr1;
- tree address_offset = ssize_int (0), address_misalign = ssize_int (0);
- tree dummy;
- struct ptr_info_def *dummy1;
- subvar_t dummy2;
-
- switch (TREE_CODE (expr))
- {
- case PLUS_EXPR:
- case MINUS_EXPR:
- /* EXPR is of form {base +/- offset} (or {offset +/- base}). */
- oprnd0 = TREE_OPERAND (expr, 0);
- oprnd1 = TREE_OPERAND (expr, 1);
-
- STRIP_NOPS (oprnd0);
- STRIP_NOPS (oprnd1);
-
- /* Recursively try to find the base of the address contained in EXPR.
- For offset, the returned base will be NULL. */
- base_addr0 = vect_address_analysis (oprnd0, stmt, is_read, vectype, dr,
- &address_offset, &address_misalign, step,
- base_aligned);
-
- base_addr1 = vect_address_analysis (oprnd1, stmt, is_read, vectype, dr,
- &address_offset, &address_misalign, step,
- base_aligned);
-
- /* We support cases where only one of the operands contains an
- address. */
- if ((base_addr0 && base_addr1) || (!base_addr0 && !base_addr1))
- return NULL_TREE;
-
- /* To revert STRIP_NOPS. */
- oprnd0 = TREE_OPERAND (expr, 0);
- oprnd1 = TREE_OPERAND (expr, 1);
-
- offset_expr = base_addr0 ?
- fold_convert (ssizetype, oprnd1) : fold_convert (ssizetype, oprnd0);
-
- /* EXPR is of form {base +/- offset} (or {offset +/- base}). If offset is
- a number, we can add it to the misalignment value calculated for base,
- otherwise, misalignment is NULL. */
- if (TREE_CODE (offset_expr) == INTEGER_CST && address_misalign)
- *misalign = size_binop (TREE_CODE (expr), address_misalign,
- offset_expr);
- else
- *misalign = NULL_TREE;
-
- /* Combine offset (from EXPR {base + offset}) with the offset calculated
- for base. */
- *offset = size_binop (TREE_CODE (expr), address_offset, offset_expr);
- return base_addr0 ? base_addr0 : base_addr1;
-
- case ADDR_EXPR:
- base_address = vect_object_analysis (TREE_OPERAND (expr, 0), stmt,
- is_read, vectype, &dr, offset,
- misalign, step, base_aligned,
- &dummy, &dummy1, &dummy2);
- return base_address;
-
- case SSA_NAME:
- if (!POINTER_TYPE_P (TREE_TYPE (expr)))
- return NULL_TREE;
-
- if (TYPE_ALIGN (TREE_TYPE (TREE_TYPE (expr))) < TYPE_ALIGN (vectype))
- {
- if (vect_get_ptr_offset (expr, vectype, misalign))
- *base_aligned = true;
- else
- *base_aligned = false;
- }
- else
- {
- *base_aligned = true;
- *misalign = ssize_int (0);
- }
- *offset = ssize_int (0);
- *step = ssize_int (0);
- return expr;
-
- default:
- return NULL_TREE;
- }
-}
-
-
-/* Function vect_object_analysis
-
- Return the BASE of the data reference MEMREF.
- Also compute the INITIAL_OFFSET from BASE, MISALIGN and STEP.
- E.g., for EXPR a.b[i] + 4B, BASE is a, and OFFSET is the overall offset
- 'a.b[i] + 4B' from a (can be an expression), MISALIGN is an OFFSET
- instantiated with initial_conditions of access_functions of variables,
- modulo alignment, and STEP is the evolution of the DR_REF in this loop.
-
- Function get_inner_reference is used for the above in case of ARRAY_REF and
- COMPONENT_REF.
-
- The structure of the function is as follows:
- Part 1:
- Case 1. For handled_component_p refs
- 1.1 call get_inner_reference
- 1.1.1 analyze offset expr received from get_inner_reference
- 1.2. build data-reference structure for MEMREF
- (fall through with BASE)
- Case 2. For declarations
- 2.1 check alignment
- 2.2 update DR_BASE_NAME if necessary for alias
- Case 3. For INDIRECT_REFs
- 3.1 get the access function
- 3.2 analyze evolution of MEMREF
- 3.3 set data-reference structure for MEMREF
- 3.4 call vect_address_analysis to analyze INIT of the access function
-
- Part 2:
- Combine the results of object and address analysis to calculate
- INITIAL_OFFSET, STEP and misalignment info.
-
- Input:
- MEMREF - the memory reference that is being analyzed
- STMT - the statement that contains MEMREF
- IS_READ - TRUE if STMT reads from MEMREF, FALSE if writes to MEMREF
- VECTYPE - the type that defines the alignment (i.e, we compute
- alignment relative to TYPE_ALIGN(VECTYPE))
-
- Output:
- BASE_ADDRESS (returned value) - the base address of the data reference MEMREF
- E.g, if MEMREF is a.b[k].c[i][j] the returned
- base is &a.
- DR - data_reference struct for MEMREF
- INITIAL_OFFSET - initial offset of MEMREF from BASE (an expression)
- MISALIGN - offset of MEMREF from BASE in bytes (a constant) or NULL_TREE if
- the computation is impossible
- STEP - evolution of the DR_REF in the loop
- BASE_ALIGNED - indicates if BASE is aligned
- MEMTAG - memory tag for aliasing purposes
- PTR_INFO - NULL or points-to aliasing info from a pointer SSA_NAME
- SUBVAR - Sub-variables of the variable
-
- If something unexpected is encountered (an unsupported form of data-ref),
- then NULL_TREE is returned. */
-
-static tree
-vect_object_analysis (tree memref, tree stmt, bool is_read,
- tree vectype, struct data_reference **dr,
- tree *offset, tree *misalign, tree *step,
- bool *base_aligned, tree *memtag,
- struct ptr_info_def **ptr_info, subvar_t *subvars)
-{
- tree base = NULL_TREE, base_address = NULL_TREE;
- tree object_offset = ssize_int (0), object_misalign = ssize_int (0);
- tree object_step = ssize_int (0), address_step = ssize_int (0);
- bool object_base_aligned = true, address_base_aligned = true;
- tree address_offset = ssize_int (0), address_misalign = ssize_int (0);
- HOST_WIDE_INT pbitsize, pbitpos;
- tree poffset, bit_pos_in_bytes;
- enum machine_mode pmode;
- int punsignedp, pvolatilep;
- tree ptr_step = ssize_int (0), ptr_init = NULL_TREE;
- stmt_vec_info stmt_info = vinfo_for_stmt (stmt);
- loop_vec_info loop_vinfo = STMT_VINFO_LOOP_VINFO (stmt_info);
- struct loop *loop = LOOP_VINFO_LOOP (loop_vinfo);
- struct data_reference *ptr_dr = NULL;
- tree access_fn, evolution_part, address_to_analyze;
-
- *ptr_info = NULL;
-
- /* Part 1: */
- /* Case 1. handled_component_p refs. */
- if (handled_component_p (memref))
- {
- /* 1.1 call get_inner_reference. */
- /* Find the base and the offset from it. */
- base = get_inner_reference (memref, &pbitsize, &pbitpos, &poffset,
- &pmode, &punsignedp, &pvolatilep, false);
- if (!base)
- return NULL_TREE;
-
- /* 1.1.1 analyze offset expr received from get_inner_reference. */
- if (poffset
- && !vect_analyze_offset_expr (poffset, loop, TYPE_SIZE_UNIT (vectype),
- &object_offset, &object_misalign, &object_step))
- {
- if (vect_print_dump_info (REPORT_DETAILS))
- {
- fprintf (vect_dump, "failed to compute offset or step for ");
- print_generic_expr (vect_dump, memref, TDF_SLIM);
- }
- return NULL_TREE;
- }
-
- /* Add bit position to OFFSET and MISALIGN. */
-
- bit_pos_in_bytes = ssize_int (pbitpos/BITS_PER_UNIT);
- /* Check that there is no remainder in bits. */
- if (pbitpos%BITS_PER_UNIT)
- {
- if (vect_print_dump_info (REPORT_DETAILS))
- fprintf (vect_dump, "bit offset alignment.");
- return NULL_TREE;
- }
- object_offset = size_binop (PLUS_EXPR, bit_pos_in_bytes, object_offset);
- if (object_misalign)
- object_misalign = size_binop (PLUS_EXPR, object_misalign,
- bit_pos_in_bytes);
-
- /* Create data-reference for MEMREF. TODO: handle COMPONENT_REFs. */
- if (!(*dr))
- {
- if (TREE_CODE (memref) == ARRAY_REF)
- *dr = analyze_array (stmt, memref, is_read);
- else
- /* FORNOW. */
- return NULL_TREE;
- }
- memref = base; /* To continue analysis of BASE. */
- /* fall through */
- }
-
- /* Part 1: Case 2. Declarations. */
- if (DECL_P (memref))
- {
- /* We expect to get a decl only if we already have a DR. */
- if (!(*dr))
- {
- if (vect_print_dump_info (REPORT_DETAILS))
- {
- fprintf (vect_dump, "unhandled decl ");
- print_generic_expr (vect_dump, memref, TDF_SLIM);
- }
- return NULL_TREE;
- }
-
- /* 2.1 check the alignment. */
- if (DECL_ALIGN (memref) >= TYPE_ALIGN (vectype))
- object_base_aligned = true;
- else
- object_base_aligned = false;
-
- /* 2.2 update DR_BASE_NAME if necessary. */
- if (!DR_BASE_NAME ((*dr)))
- /* For alias analysis. In case the analysis of INDIRECT_REF brought
- us to object. */
- DR_BASE_NAME ((*dr)) = memref;
-
- if (SSA_VAR_P (memref) && var_can_have_subvars (memref))
- *subvars = get_subvars_for_var (memref);
- base_address = build_fold_addr_expr (memref);
- *memtag = memref;
- }
-
- /* Part 1: Case 3. INDIRECT_REFs. */
- else if (TREE_CODE (memref) == INDIRECT_REF)
- {
- tree ptr_ref = TREE_OPERAND (memref, 0);
- if (TREE_CODE (ptr_ref) == SSA_NAME)
- *ptr_info = SSA_NAME_PTR_INFO (ptr_ref);
-
- /* 3.1 get the access function. */
- access_fn = analyze_scalar_evolution (loop, ptr_ref);
- if (!access_fn)
- {
- if (vect_print_dump_info (REPORT_UNVECTORIZED_LOOPS))
- fprintf (vect_dump, "not vectorized: complicated pointer access.");
- return NULL_TREE;
- }
- if (vect_print_dump_info (REPORT_DETAILS))
- {
- fprintf (vect_dump, "Access function of ptr: ");
- print_generic_expr (vect_dump, access_fn, TDF_SLIM);
- }
-
- /* 3.2 analyze evolution of MEMREF. */
- evolution_part = evolution_part_in_loop_num (access_fn, loop->num);
- if (evolution_part)
- {
- ptr_dr = vect_analyze_pointer_ref_access (memref, stmt, is_read,
- access_fn, &ptr_init, &ptr_step);
- if (!(ptr_dr))
- return NULL_TREE;
-
- object_step = size_binop (PLUS_EXPR, object_step, ptr_step);
- address_to_analyze = ptr_init;
- }
- else
- {
- if (!(*dr))
- {
- if (vect_print_dump_info (REPORT_UNVECTORIZED_LOOPS))
- fprintf (vect_dump, "not vectorized: ptr is loop invariant.");
- return NULL_TREE;
- }
- /* Since there exists DR for MEMREF, we are analyzing the init of
- the access function, which not necessary has evolution in the
- loop. */
- address_to_analyze = initial_condition_in_loop_num (access_fn,
- loop->num);
- }
-
- /* 3.3 set data-reference structure for MEMREF. */
- *dr = (*dr) ? *dr : ptr_dr;
-
- /* 3.4 call vect_address_analysis to analyze INIT of the access
- function. */
- base_address = vect_address_analysis (address_to_analyze, stmt, is_read,
- vectype, *dr, &address_offset, &address_misalign,
- &address_step, &address_base_aligned);
- if (!base_address)
- return NULL_TREE;
-
- switch (TREE_CODE (base_address))
- {
- case SSA_NAME:
- *memtag = get_var_ann (SSA_NAME_VAR (base_address))->type_mem_tag;
- if (!(*memtag) && TREE_CODE (TREE_OPERAND (memref, 0)) == SSA_NAME)
- *memtag = get_var_ann (
- SSA_NAME_VAR (TREE_OPERAND (memref, 0)))->type_mem_tag;
- break;
- case ADDR_EXPR:
- *memtag = TREE_OPERAND (base_address, 0);
- break;
- default:
- if (vect_print_dump_info (REPORT_UNVECTORIZED_LOOPS))
- {
- fprintf (vect_dump, "not vectorized: no memtag ref: ");
- print_generic_expr (vect_dump, memref, TDF_SLIM);
- }
- return NULL_TREE;
- }
- }
-
- if (!base_address)
- /* MEMREF cannot be analyzed. */
- return NULL_TREE;
-
- if (SSA_VAR_P (*memtag) && var_can_have_subvars (*memtag))
- *subvars = get_subvars_for_var (*memtag);
-
- /* Part 2: Combine the results of object and address analysis to calculate
- INITIAL_OFFSET, STEP and misalignment info. */
- *offset = size_binop (PLUS_EXPR, object_offset, address_offset);
- if (object_misalign && address_misalign)
- *misalign = size_binop (PLUS_EXPR, object_misalign, address_misalign);
- else
- *misalign = NULL_TREE;
- *step = size_binop (PLUS_EXPR, object_step, address_step);
- *base_aligned = object_base_aligned && address_base_aligned;
-
- if (vect_print_dump_info (REPORT_DETAILS))
- {
- fprintf (vect_dump, "Results of object analysis for: ");
- print_generic_expr (vect_dump, memref, TDF_SLIM);
- fprintf (vect_dump, "\n\tbase_address: ");
- print_generic_expr (vect_dump, base_address, TDF_SLIM);
- fprintf (vect_dump, "\n\toffset: ");
- print_generic_expr (vect_dump, *offset, TDF_SLIM);
- fprintf (vect_dump, "\n\tstep: ");
- print_generic_expr (vect_dump, *step, TDF_SLIM);
- fprintf (vect_dump, "\n\tbase aligned %d\n\tmisalign: ", *base_aligned);
- print_generic_expr (vect_dump, *misalign, TDF_SLIM);
- }
- return base_address;
-}
-
-
/* Function vect_analyze_data_refs.
- Find all the data references in the loop.
+ Find all the data references in the loop.
- The general structure of the analysis of data refs in the vectorizer is as
+ The general structure of the analysis of data refs in the vectorizer is as
follows:
- 1- vect_analyze_data_refs(loop):
- Find and analyze all data-refs in the loop:
- foreach ref
- base_address = vect_object_analysis(ref)
- 1.1- vect_object_analysis(ref):
- Analyze ref, and build a DR (data_reference struct) for it;
- compute base, initial_offset, step and alignment.
- Call get_inner_reference for refs handled in this function.
- Call vect_addr_analysis(addr) to analyze pointer type expressions.
- Set ref_stmt.base, ref_stmt.initial_offset, ref_stmt.alignment,
- ref_stmt.memtag, ref_stmt.ptr_info and ref_stmt.step accordingly.
- 2- vect_analyze_dependences(): apply dependence testing using ref_stmt.DR
+ 1- vect_analyze_data_refs(loop): call compute_data_dependences_for_loop to
+ find and analyze all data-refs in the loop and their dependences.
+ 2- vect_analyze_dependences(): apply dependence testing using ddrs.
3- vect_analyze_drs_alignment(): check that ref_stmt.alignment is ok.
4- vect_analyze_drs_access(): check that ref_stmt.step is ok.
- FORNOW: Handle aligned INDIRECT_REFs and ARRAY_REFs
- which base is really an array (not a pointer) and which alignment
- can be forced. This restriction will be relaxed. */
+*/
static bool
-vect_analyze_data_refs (loop_vec_info loop_vinfo)
+vect_analyze_data_refs (loop_vec_info loop_vinfo)
{
struct loop *loop = LOOP_VINFO_LOOP (loop_vinfo);
- basic_block *bbs = LOOP_VINFO_BBS (loop_vinfo);
- int nbbs = loop->num_nodes;
- block_stmt_iterator si;
- int j;
- struct data_reference *dr;
+ unsigned int i;
+ varray_type datarefs;
+ tree scalar_type;
if (vect_print_dump_info (REPORT_DETAILS))
fprintf (vect_dump, "=== vect_analyze_data_refs ===");
- for (j = 0; j < nbbs; j++)
- {
- basic_block bb = bbs[j];
- for (si = bsi_start (bb); !bsi_end_p (si); bsi_next (&si))
- {
- bool is_read = false;
- tree stmt = bsi_stmt (si);
- stmt_vec_info stmt_info = vinfo_for_stmt (stmt);
- varray_type *datarefs = NULL;
- tree memref = NULL;
- tree scalar_type, vectype;
- tree base, offset, misalign, step, tag;
- struct ptr_info_def *ptr_info;
- bool base_aligned;
- subvar_t subvars = NULL;
- bool no_vuse, no_vmaymust;
-
- /* Assumption: there exists a data-ref in stmt, if and only if
- it has vuses/vdefs. */
-
- no_vuse = ZERO_SSA_OPERANDS (stmt, SSA_OP_VUSE);
- no_vmaymust = ZERO_SSA_OPERANDS (stmt,
- SSA_OP_VMAYDEF | SSA_OP_VMUSTDEF);
- if (no_vuse && no_vmaymust)
- continue;
+ compute_data_dependences_for_loop (loop, false,
+ &(LOOP_VINFO_DATAREFS (loop_vinfo)),
+ &(LOOP_VINFO_DDRS (loop_vinfo)));
- if (!no_vuse && !no_vmaymust)
- {
- if (vect_print_dump_info (REPORT_DETAILS))
- {
- fprintf (vect_dump, "unexpected vdefs and vuses in stmt: ");
- print_generic_expr (vect_dump, stmt, TDF_SLIM);
- }
- return false;
- }
-
- if (TREE_CODE (stmt) != MODIFY_EXPR)
- {
- if (vect_print_dump_info (REPORT_DETAILS))
- {
- fprintf (vect_dump, "unexpected vops in stmt: ");
- print_generic_expr (vect_dump, stmt, TDF_SLIM);
- }
- return false;
- }
-
- if (!no_vuse)
- {
- memref = TREE_OPERAND (stmt, 1);
- datarefs = &(LOOP_VINFO_DATAREF_READS (loop_vinfo));
- is_read = true;
- }
- else /* vdefs */
- {
- memref = TREE_OPERAND (stmt, 0);
- datarefs = &(LOOP_VINFO_DATAREF_WRITES (loop_vinfo));
- is_read = false;
- }
-
- scalar_type = TREE_TYPE (memref);
- vectype = get_vectype_for_scalar_type (scalar_type);
- if (!vectype)
- {
- if (vect_print_dump_info (REPORT_DETAILS))
- {
- fprintf (vect_dump, "no vectype for stmt: ");
- print_generic_expr (vect_dump, stmt, TDF_SLIM);
- fprintf (vect_dump, " scalar_type: ");
- print_generic_expr (vect_dump, scalar_type, TDF_DETAILS);
- }
- /* It is not possible to vectorize this data reference. */
- return false;
- }
- /* Analyze MEMREF. If it is of a supported form, build data_reference
- struct for it (DR). */
- dr = NULL;
- base = vect_object_analysis (memref, stmt, is_read, vectype, &dr,
- &offset, &misalign, &step,
- &base_aligned, &tag, &ptr_info,
- &subvars);
- if (!base)
- {
- if (vect_print_dump_info (REPORT_UNVECTORIZED_LOOPS))
- {
- fprintf (vect_dump, "not vectorized: unhandled data ref: ");
- print_generic_expr (vect_dump, stmt, TDF_SLIM);
- }
- return false;
- }
- STMT_VINFO_VECT_DR_BASE_ADDRESS (stmt_info) = base;
- STMT_VINFO_VECT_INIT_OFFSET (stmt_info) = offset;
- STMT_VINFO_VECT_STEP (stmt_info) = step;
- STMT_VINFO_VECT_MISALIGNMENT (stmt_info) = misalign;
- STMT_VINFO_VECT_BASE_ALIGNED_P (stmt_info) = base_aligned;
- STMT_VINFO_MEMTAG (stmt_info) = tag;
- STMT_VINFO_PTR_INFO (stmt_info) = ptr_info;
- STMT_VINFO_SUBVARS (stmt_info) = subvars;
- STMT_VINFO_VECTYPE (stmt_info) = vectype;
- VARRAY_PUSH_GENERIC_PTR (*datarefs, dr);
- STMT_VINFO_DATA_REF (stmt_info) = dr;
- }
+ /* Go through the data-refs, check that the analysis succeeded. Update pointer
+ from stmt_vec_info struct to DR and vectype. */
+ datarefs = LOOP_VINFO_DATAREFS (loop_vinfo);
+ for (i = 0; i < VARRAY_ACTIVE_SIZE (datarefs); i++)
+ {
+ struct data_reference *dr = VARRAY_GENERIC_PTR (datarefs, i);
+ tree stmt;
+ stmt_vec_info stmt_info;
+
+ if (!dr || !DR_REF (dr))
+ {
+ if (vect_print_dump_info (REPORT_UNVECTORIZED_LOOPS))
+ fprintf (vect_dump, "not vectorized: unhandled data-ref ");
+ return false;
+ }
+
+ /* Update DR field in stmt_vec_info struct. */
+ stmt = DR_STMT (dr);
+ stmt_info = vinfo_for_stmt (stmt);
+
+ if (STMT_VINFO_DATA_REF (stmt_info))
+ {
+ if (vect_print_dump_info (REPORT_UNVECTORIZED_LOOPS))
+ {
+ fprintf (vect_dump,
+ "not vectorized: more than one data ref in stmt: ");
+ print_generic_expr (vect_dump, stmt, TDF_SLIM);
+ }
+ return false;
+ }
+ STMT_VINFO_DATA_REF (stmt_info) = dr;
+
+ /* Check that analysis of the data-ref succeeded. */
+ if (!DR_BASE_ADDRESS (dr) || !DR_OFFSET (dr) || !DR_INIT (dr)
+ || !DR_STEP (dr))
+ {
+ if (vect_print_dump_info (REPORT_UNVECTORIZED_LOOPS))
+ {
+ fprintf (vect_dump, "not vectorized: data ref analysis failed ");
+ print_generic_expr (vect_dump, stmt, TDF_SLIM);
+ }
+ return false;
+ }
+ if (!DR_MEMTAG (dr))
+ {
+ if (vect_print_dump_info (REPORT_UNVECTORIZED_LOOPS))
+ {
+ fprintf (vect_dump, "not vectorized: no memory tag for ");
+ print_generic_expr (vect_dump, DR_REF (dr), TDF_SLIM);
+ }
+ return false;
+ }
+
+ /* Set vectype for STMT. */
+ scalar_type = TREE_TYPE (DR_REF (dr));
+ STMT_VINFO_VECTYPE (stmt_info) =
+ get_vectype_for_scalar_type (scalar_type);
+ if (!STMT_VINFO_VECTYPE (stmt_info))
+ {
+ if (vect_print_dump_info (REPORT_UNVECTORIZED_LOOPS))
+ {
+ fprintf (vect_dump,
+ "not vectorized: no vectype for stmt: ");
+ print_generic_expr (vect_dump, stmt, TDF_SLIM);
+ fprintf (vect_dump, " scalar_type: ");
+ print_generic_expr (vect_dump, scalar_type, TDF_DETAILS);
+ }
+ return false;
+ }
}
-
+
return true;
}
diff --git a/gcc/tree-vect-transform.c b/gcc/tree-vect-transform.c
index c2a8f0d..9dab8bc 100644
--- a/gcc/tree-vect-transform.c
+++ b/gcc/tree-vect-transform.c
@@ -189,8 +189,7 @@ vect_create_addr_base_for_vector_ref (tree stmt,
{
stmt_vec_info stmt_info = vinfo_for_stmt (stmt);
struct data_reference *dr = STMT_VINFO_DATA_REF (stmt_info);
- tree data_ref_base =
- unshare_expr (STMT_VINFO_VECT_DR_BASE_ADDRESS (stmt_info));
+ tree data_ref_base = unshare_expr (DR_BASE_ADDRESS (dr));
tree base_name = build_fold_indirect_ref (data_ref_base);
tree ref = DR_REF (dr);
tree scalar_type = TREE_TYPE (ref);
@@ -199,9 +198,11 @@ vect_create_addr_base_for_vector_ref (tree stmt,
tree new_temp;
tree addr_base, addr_expr;
tree dest, new_stmt;
- tree base_offset = unshare_expr (STMT_VINFO_VECT_INIT_OFFSET (stmt_info));
+ tree base_offset = unshare_expr (DR_OFFSET (dr));
+ tree init = unshare_expr (DR_INIT (dr));
/* Create base_offset */
+ base_offset = size_binop (PLUS_EXPR, base_offset, init);
dest = create_tmp_var (TREE_TYPE (base_offset), "base_off");
add_referenced_tmp_var (dest);
base_offset = force_gimple_operand (base_offset, &new_stmt, false, dest);
@@ -212,7 +213,7 @@ vect_create_addr_base_for_vector_ref (tree stmt,
tree tmp = create_tmp_var (TREE_TYPE (base_offset), "offset");
add_referenced_tmp_var (tmp);
offset = fold_build2 (MULT_EXPR, TREE_TYPE (offset), offset,
- STMT_VINFO_VECT_STEP (stmt_info));
+ DR_STEP (dr));
base_offset = fold_build2 (PLUS_EXPR, TREE_TYPE (base_offset),
base_offset, offset);
base_offset = force_gimple_operand (base_offset, &new_stmt, false, tmp);
@@ -328,9 +329,9 @@ vect_create_data_ref_ptr (tree stmt, block_stmt_iterator *bsi, tree offset,
tree ptr_update;
tree data_ref_ptr;
tree type, tmp, size;
+ struct data_reference *dr = STMT_VINFO_DATA_REF (stmt_info);
- base_name = build_fold_indirect_ref (unshare_expr (
- STMT_VINFO_VECT_DR_BASE_ADDRESS (stmt_info)));
+ base_name = build_fold_indirect_ref (unshare_expr (DR_BASE_ADDRESS (dr)));
if (vect_print_dump_info (REPORT_DETAILS))
{
@@ -357,9 +358,9 @@ vect_create_data_ref_ptr (tree stmt, block_stmt_iterator *bsi, tree offset,
/** (2) Add aliasing information to the new vector-pointer:
- (The points-to info (SSA_NAME_PTR_INFO) may be defined later.) **/
+ (The points-to info (DR_PTR_INFO) may be defined later.) **/
- tag = STMT_VINFO_MEMTAG (stmt_info);
+ tag = DR_MEMTAG (dr);
gcc_assert (tag);
/* If tag is a variable (and NOT_A_TAG) than a new type alias
@@ -369,7 +370,7 @@ vect_create_data_ref_ptr (tree stmt, block_stmt_iterator *bsi, tree offset,
else
var_ann (vect_ptr)->type_mem_tag = tag;
- var_ann (vect_ptr)->subvars = STMT_VINFO_SUBVARS (stmt_info);
+ var_ann (vect_ptr)->subvars = DR_SUBVARS (dr);
/** (3) Calculate the initial address the vector-pointer, and set
the vector-pointer to point to it before the loop: **/
@@ -397,9 +398,8 @@ vect_create_data_ref_ptr (tree stmt, block_stmt_iterator *bsi, tree offset,
if (only_init) /* No update in loop is required. */
{
/* Copy the points-to information if it exists. */
- if (STMT_VINFO_PTR_INFO (stmt_info))
- duplicate_ssa_name_ptr_info (vect_ptr_init,
- STMT_VINFO_PTR_INFO (stmt_info));
+ if (DR_PTR_INFO (dr))
+ duplicate_ssa_name_ptr_info (vect_ptr_init, DR_PTR_INFO (dr));
return vect_ptr_init;
}
@@ -433,8 +433,8 @@ vect_create_data_ref_ptr (tree stmt, block_stmt_iterator *bsi, tree offset,
data_ref_ptr = TREE_OPERAND (vec_stmt, 0);
/* Copy the points-to information if it exists. */
- if (STMT_VINFO_PTR_INFO (stmt_info))
- duplicate_ssa_name_ptr_info (data_ref_ptr, STMT_VINFO_PTR_INFO (stmt_info));
+ if (DR_PTR_INFO (dr))
+ duplicate_ssa_name_ptr_info (data_ref_ptr, DR_PTR_INFO (dr));
return data_ref_ptr;
}
@@ -2625,18 +2625,16 @@ vect_gen_niters_for_prolog_loop (loop_vec_info loop_vinfo, tree loop_niters)
NITERS iterations were peeled from LOOP. DR represents a data reference
in LOOP. This function updates the information recorded in DR to
account for the fact that the first NITERS iterations had already been
- executed. Specifically, it updates the OFFSET field of stmt_info. */
+ executed. Specifically, it updates the OFFSET field of DR. */
static void
vect_update_init_of_dr (struct data_reference *dr, tree niters)
{
- stmt_vec_info stmt_info = vinfo_for_stmt (DR_STMT (dr));
- tree offset = STMT_VINFO_VECT_INIT_OFFSET (stmt_info);
+ tree offset = DR_OFFSET (dr);
- niters = fold_build2 (MULT_EXPR, TREE_TYPE (niters), niters,
- STMT_VINFO_VECT_STEP (stmt_info));
+ niters = fold_build2 (MULT_EXPR, TREE_TYPE (niters), niters, DR_STEP (dr));
offset = fold_build2 (PLUS_EXPR, TREE_TYPE (offset), offset, niters);
- STMT_VINFO_VECT_INIT_OFFSET (stmt_info) = offset;
+ DR_OFFSET (dr) = offset;
}
@@ -2652,21 +2650,14 @@ static void
vect_update_inits_of_drs (loop_vec_info loop_vinfo, tree niters)
{
unsigned int i;
- varray_type loop_write_datarefs = LOOP_VINFO_DATAREF_WRITES (loop_vinfo);
- varray_type loop_read_datarefs = LOOP_VINFO_DATAREF_READS (loop_vinfo);
+ varray_type datarefs = LOOP_VINFO_DATAREFS (loop_vinfo);
if (vect_dump && (dump_flags & TDF_DETAILS))
fprintf (vect_dump, "=== vect_update_inits_of_dr ===");
- for (i = 0; i < VARRAY_ACTIVE_SIZE (loop_write_datarefs); i++)
- {
- struct data_reference *dr = VARRAY_GENERIC_PTR (loop_write_datarefs, i);
- vect_update_init_of_dr (dr, niters);
- }
-
- for (i = 0; i < VARRAY_ACTIVE_SIZE (loop_read_datarefs); i++)
+ for (i = 0; i < VARRAY_ACTIVE_SIZE (datarefs); i++)
{
- struct data_reference *dr = VARRAY_GENERIC_PTR (loop_read_datarefs, i);
+ struct data_reference *dr = VARRAY_GENERIC_PTR (datarefs, i);
vect_update_init_of_dr (dr, niters);
}
}
diff --git a/gcc/tree-vectorizer.c b/gcc/tree-vectorizer.c
index af5382c..4a9bbe8 100644
--- a/gcc/tree-vectorizer.c
+++ b/gcc/tree-vectorizer.c
@@ -1347,14 +1347,6 @@ new_stmt_vec_info (tree stmt, loop_vec_info loop_vinfo)
STMT_VINFO_DEF_TYPE (res) = vect_unknown_def_type;
else
STMT_VINFO_DEF_TYPE (res) = vect_loop_def;
- STMT_VINFO_MEMTAG (res) = NULL;
- STMT_VINFO_PTR_INFO (res) = NULL;
- STMT_VINFO_SUBVARS (res) = NULL;
- STMT_VINFO_VECT_DR_BASE_ADDRESS (res) = NULL;
- STMT_VINFO_VECT_INIT_OFFSET (res) = NULL_TREE;
- STMT_VINFO_VECT_STEP (res) = NULL_TREE;
- STMT_VINFO_VECT_BASE_ALIGNED_P (res) = false;
- STMT_VINFO_VECT_MISALIGNMENT (res) = NULL_TREE;
STMT_VINFO_SAME_ALIGN_REFS (res) = VEC_alloc (dr_p, heap, 5);
return res;
@@ -1407,10 +1399,8 @@ new_loop_vec_info (struct loop *loop)
LOOP_VINFO_VECTORIZABLE_P (res) = 0;
LOOP_PEELING_FOR_ALIGNMENT (res) = 0;
LOOP_VINFO_VECT_FACTOR (res) = 0;
- VARRAY_GENERIC_PTR_INIT (LOOP_VINFO_DATAREF_WRITES (res), 20,
- "loop_write_datarefs");
- VARRAY_GENERIC_PTR_INIT (LOOP_VINFO_DATAREF_READS (res), 20,
- "loop_read_datarefs");
+ VARRAY_GENERIC_PTR_INIT (LOOP_VINFO_DATAREFS (res), 20, "loop_datarefs");
+ VARRAY_GENERIC_PTR_INIT (LOOP_VINFO_DDRS (res), 20, "loop_ddrs");
LOOP_VINFO_UNALIGNED_DR (res) = NULL;
return res;
@@ -1470,39 +1460,13 @@ destroy_loop_vec_info (loop_vec_info loop_vinfo)
}
free (LOOP_VINFO_BBS (loop_vinfo));
- varray_clear (LOOP_VINFO_DATAREF_WRITES (loop_vinfo));
- varray_clear (LOOP_VINFO_DATAREF_READS (loop_vinfo));
+ varray_clear (LOOP_VINFO_DATAREFS (loop_vinfo));
+ varray_clear (LOOP_VINFO_DDRS (loop_vinfo));
free (loop_vinfo);
}
-/* Function vect_strip_conversions
-
- Strip conversions that don't narrow the mode. */
-
-tree
-vect_strip_conversion (tree expr)
-{
- tree to, ti, oprnd0;
-
- while (TREE_CODE (expr) == NOP_EXPR || TREE_CODE (expr) == CONVERT_EXPR)
- {
- to = TREE_TYPE (expr);
- oprnd0 = TREE_OPERAND (expr, 0);
- ti = TREE_TYPE (oprnd0);
-
- if (!INTEGRAL_TYPE_P (to) || !INTEGRAL_TYPE_P (ti))
- return NULL_TREE;
- if (GET_MODE_SIZE (TYPE_MODE (to)) < GET_MODE_SIZE (TYPE_MODE (ti)))
- return NULL_TREE;
-
- expr = oprnd0;
- }
- return expr;
-}
-
-
/* Function vect_force_dr_alignment_p.
Returns whether the alignment of a DECL can be forced to be aligned
diff --git a/gcc/tree-vectorizer.h b/gcc/tree-vectorizer.h
index 87d3138..5fdca3d 100644
--- a/gcc/tree-vectorizer.h
+++ b/gcc/tree-vectorizer.h
@@ -73,6 +73,7 @@ enum verbosity_levels {
REPORT_VECTORIZED_LOOPS,
REPORT_UNVECTORIZED_LOOPS,
REPORT_ALIGNMENT,
+ REPORT_DR_DETAILS,
REPORT_BAD_FORM_LOOPS,
REPORT_OUTER_LOOPS,
REPORT_DETAILS,
@@ -116,27 +117,29 @@ typedef struct _loop_vec_info {
unaligned_dr. */
int peeling_for_alignment;
- /* All data references in the loop that are being written to. */
- varray_type data_ref_writes;
+ /* All data references in the loop. */
+ varray_type datarefs;
- /* All data references in the loop that are being read from. */
- varray_type data_ref_reads;
+ /* All data dependences in the loop. */
+ varray_type ddrs;
+ /* The loop location in the source. */
+ LOC loop_line_number;
} *loop_vec_info;
-/* Access Functions. */
-#define LOOP_VINFO_LOOP(L) (L)->loop
-#define LOOP_VINFO_BBS(L) (L)->bbs
-#define LOOP_VINFO_EXIT_COND(L) (L)->exit_cond
-#define LOOP_VINFO_NITERS(L) (L)->num_iters
-#define LOOP_VINFO_VECTORIZABLE_P(L) (L)->vectorizable
-#define LOOP_VINFO_VECT_FACTOR(L) (L)->vectorization_factor
-#define LOOP_VINFO_DATAREF_WRITES(L) (L)->data_ref_writes
-#define LOOP_VINFO_DATAREF_READS(L) (L)->data_ref_reads
-#define LOOP_VINFO_INT_NITERS(L) (TREE_INT_CST_LOW ((L)->num_iters))
+ /* Access Functions. */
+#define LOOP_VINFO_LOOP(L) (L)->loop
+#define LOOP_VINFO_BBS(L) (L)->bbs
+#define LOOP_VINFO_EXIT_COND(L) (L)->exit_cond
+#define LOOP_VINFO_NITERS(L) (L)->num_iters
+#define LOOP_VINFO_VECTORIZABLE_P(L) (L)->vectorizable
+#define LOOP_VINFO_VECT_FACTOR(L) (L)->vectorization_factor
+#define LOOP_VINFO_DATAREFS(L) (L)->datarefs
+#define LOOP_VINFO_DDRS(L) (L)->ddrs
+#define LOOP_VINFO_INT_NITERS(L) (TREE_INT_CST_LOW ((L)->num_iters))
#define LOOP_PEELING_FOR_ALIGNMENT(L) (L)->peeling_for_alignment
-#define LOOP_VINFO_UNALIGNED_DR(L) (L)->unaligned_dr
-
+#define LOOP_VINFO_UNALIGNED_DR(L) (L)->unaligned_dr
+#define LOOP_VINFO_LOC(L) (L)->loop_line_number
#define LOOP_VINFO_NITERS_KNOWN_P(L) \
(host_integerp ((L)->num_iters,0) \
@@ -192,45 +195,6 @@ typedef struct _stmt_vec_info {
/* Information about the data-ref (access function, etc). */
struct data_reference *data_ref_info;
- /* Aliasing information. This field represents the symbol that
- should be aliased by a pointer holding the address of this data
- reference. If the original data reference was a pointer
- dereference, then this field contains the memory tag that should
- be used by the new vector-pointer. */
- tree memtag;
- struct ptr_info_def *ptr_info;
- subvar_t subvars;
-
- /** The following fields are used to store the information about
- data-reference. {base_address + initial_offset} is the first location
- accessed by data-ref in the loop, and step is the stride of data-ref in
- the loop in bytes;
- e.g.:
-
- Example 1 Example 2
- data-ref a[j].b[i][j] a + 4B (a is int*)
-
- base_address &a a
- initial_offset j_0*D_j + i_0*D_i + C 4
- step D_j 4
-
- data-reference structure info:
- base_name a NULL
- access_fn <access_fns of indexes of b> (0, +, 1)
-
- **/
- /* The above base_address, offset and step. */
- tree base_address;
- tree initial_offset;
- tree step;
-
- /* Alignment information. Whether the base of the data-reference is aligned
- to vectype. */
- bool base_aligned_p;
- /* Alignment information. The offset of the data-reference from its base
- in bytes. */
- tree misalignment;
-
/* List of datarefs that are known to have the same alignment as the dataref
of this stmt. */
VEC(dr_p,heap) *same_align_refs;
@@ -249,14 +213,6 @@ typedef struct _stmt_vec_info {
#define STMT_VINFO_VECTYPE(S) (S)->vectype
#define STMT_VINFO_VEC_STMT(S) (S)->vectorized_stmt
#define STMT_VINFO_DATA_REF(S) (S)->data_ref_info
-#define STMT_VINFO_MEMTAG(S) (S)->memtag
-#define STMT_VINFO_PTR_INFO(S) (S)->ptr_info
-#define STMT_VINFO_SUBVARS(S) (S)->subvars
-#define STMT_VINFO_VECT_DR_BASE_ADDRESS(S)(S)->base_address
-#define STMT_VINFO_VECT_INIT_OFFSET(S) (S)->initial_offset
-#define STMT_VINFO_VECT_STEP(S) (S)->step
-#define STMT_VINFO_VECT_BASE_ALIGNED_P(S) (S)->base_aligned_p
-#define STMT_VINFO_VECT_MISALIGNMENT(S) (S)->misalignment
#define STMT_VINFO_SAME_ALIGN_REFS(S) (S)->same_align_refs
#define STMT_VINFO_DEF_TYPE(S) (S)->def_type
diff --git a/gcc/tree.h b/gcc/tree.h
index 10472fe..df730a5 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -4174,4 +4174,7 @@ extern void init_object_sizes (void);
extern void fini_object_sizes (void);
extern unsigned HOST_WIDE_INT compute_builtin_object_size (tree, int);
+/* In expr.c. */
+extern unsigned HOST_WIDE_INT highest_pow2_factor (tree);
+
#endif /* GCC_TREE_H */