diff options
author | Ira Rosen <irar@il.ibm.com> | 2005-07-25 12:05:07 +0000 |
---|---|---|
committer | Ira Rosen <irar@gcc.gnu.org> | 2005-07-25 12:05:07 +0000 |
commit | 86a0740499715b497e753af5b73c33ccb934c70b (patch) | |
tree | 2c7091212ab12d18c54b6a9e333f0b9450742dab | |
parent | 4fdfb2046e90d49c41efee579b8b7c76adebd26e (diff) | |
download | gcc-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
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 @@ -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 @@ -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 */ |