From: Dorit Naishlos Date: Tue, 17 Aug 2004 16:17:14 +0000 (+0000) Subject: tree-vectorizer.c: New File: loop vectorization on SSAed GIMPLE trees. X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=79fe1b3bd07343a1be36195a9053b582198a4123;p=gcc.git tree-vectorizer.c: New File: loop vectorization on SSAed GIMPLE trees. * tree-vectorizer.c: New File: loop vectorization on SSAed GIMPLE trees. * tree-vectorizer.h: New File: Same. * Makefile.in (tree-vectorizer.c, tree-vectorizer.h): Add new files. * common.opt (ftree-vectorize): New flag to enable vectorization. * timevar.def (TV_TREE_VECTORIZATION): New dump file for vectorization pass. * tree-data-ref.h (init_data_ref): Additional argument. (array_base_name_differ_p): Moved to tree-data-ref.c. * tree-data-ref.c (array_base_name_differ_p): Revised. (initialize_data_dependence_relation): Call array_base_name_differ_p with an extra argument. (analyze_all_data_dependences): Same. (init_data_ref): Additional argument is_read to set DR_IS_READ. * tree-ssa-phiopt.c (empty_block_p): Expose for usage out of this file. * tree-flow.h (vectorize_loops, empty_block_p): Add declaration. * tree-optimize.c (pass_vectorize): Schedule the vectorization pass. * tree-pass.h (tree_opt_pass pass_vectorize): Declare the new vectorization pass. * tree-ssa-loop.c (tree_ssa_loop_init): Call scev_initialize. (tree_ssa_loop_done): Call scev_finalize. (tree_vectorize): Define the new vectorization pass. * defaults.h (UNITS_PER_SIMD_WORD): Allow targets to specify the size of the vector they support (until support for multiple vector sizes is added to the vectorizer). * config/i386/i386.h (UNITS_PER_SIMD_WORD): Define. * config/rs6000/rs6000.h (UNITS_PER_SIMD_WORD): Define. * invoke.texi (fdump-tree-vect, ftree-vectorize): Add documentation. From-SVN: r86131 --- diff --git a/gcc/ChangeLog b/gcc/ChangeLog index dd4cf89d3fc..99a4aab4aa0 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,34 @@ +2004-08-17 Dorit Naishlos + + * tree-vectorizer.c: New File: loop vectorization on SSAed GIMPLE trees. + * tree-vectorizer.h: New File: Same. + * Makefile.in (tree-vectorizer.c, tree-vectorizer.h): Add new files. + * common.opt (ftree-vectorize): New flag to enable vectorization. + * timevar.def (TV_TREE_VECTORIZATION): New dump file for vectorization + pass. + * tree-data-ref.h (init_data_ref): Additional argument. + (array_base_name_differ_p): Moved to tree-data-ref.c. + * tree-data-ref.c (array_base_name_differ_p): Revised. + (initialize_data_dependence_relation): Call array_base_name_differ_p + with an extra argument. + (analyze_all_data_dependences): Same. + (init_data_ref): Additional argument is_read to set DR_IS_READ. + * tree-ssa-phiopt.c (empty_block_p): Expose for usage out of this file. + * tree-flow.h (vectorize_loops, empty_block_p): Add declaration. + * tree-optimize.c (pass_vectorize): Schedule the vectorization pass. + * tree-pass.h (tree_opt_pass pass_vectorize): Declare the new + vectorization pass. + * tree-ssa-loop.c (tree_ssa_loop_init): Call scev_initialize. + (tree_ssa_loop_done): Call scev_finalize. + (tree_vectorize): Define the new vectorization pass. + * defaults.h (UNITS_PER_SIMD_WORD): Allow targets to specify the size of + the vector they support (until support for multiple vector sizes is + added to the vectorizer). + * config/i386/i386.h (UNITS_PER_SIMD_WORD): Define. + * config/rs6000/rs6000.h (UNITS_PER_SIMD_WORD): Define. + * invoke.texi (fdump-tree-vect, ftree-vectorize): Add + documentation. + 2004-08-17 Nathan Sidwell * objc/objc-act.c (build_protocol_initializer): Fix build_int_cst diff --git a/gcc/Makefile.in b/gcc/Makefile.in index f9c03ea9e14..57939960d0d 100644 --- a/gcc/Makefile.in +++ b/gcc/Makefile.in @@ -887,6 +887,7 @@ OBJS-common = \ tree-ssa-dom.o domwalk.o tree-tailcall.o gimple-low.o tree-iterator.o \ tree-phinodes.o tree-ssanames.o tree-sra.o tree-complex.o tree-ssa-loop.o \ tree-ssa-loop-niter.o tree-ssa-loop-manip.o tree-ssa-threadupdate.o \ + tree-vectorizer.o \ alias.o bb-reorder.o bitmap.o builtins.o caller-save.o calls.o \ cfg.o cfganal.o cfgbuild.o cfgcleanup.o cfglayout.o cfgloop.o \ cfgloopanal.o cfgloopmanip.o loop-init.o loop-unswitch.o loop-unroll.o \ @@ -1727,6 +1728,10 @@ tree-data-ref.o: tree-data-ref.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ errors.h $(GGC_H) $(TREE_H) $(RTL_H) $(BASIC_BLOCK_H) diagnostic.h \ $(TREE_FLOW_H) $(TREE_DUMP_H) $(TIMEVAR_H) cfgloop.h \ tree-data-ref.h $(SCEV_H) tree-pass.h lambda.h +tree-vectorizer.o: tree-vectorizer.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ + errors.h $(GGC_H) $(OPTABS_H) $(TREE_H) $(RTL_H) $(BASIC_BLOCK_H) diagnostic.h \ + $(TREE_FLOW_H) $(TREE_DUMP_H) $(TIMEVAR_H) cfgloop.h tree-pass.h \ + tree-vectorizer.h tree-data-ref.h $(SCEV_H) tree-gimple.o : tree-gimple.c $(CONFIG_H) $(SYSTEM_H) $(TREE_H) $(EXPR_H) \ $(RTL_H) $(TREE_GIMPLE_H) $(TM_H) coretypes.h bitmap.h $(GGC_H) tree-mudflap.o : $(CONFIG_H) errors.h $(SYSTEM_H) $(TREE_H) tree-inline.h \ diff --git a/gcc/common.opt b/gcc/common.opt index 7694df121c6..6c855a63390 100644 --- a/gcc/common.opt +++ b/gcc/common.opt @@ -907,6 +907,10 @@ fvar-tracking Common Report Var(flag_var_tracking) VarExists Perform variable tracking +ftree-vectorize +Common Report Var(flag_tree_vectorize) +Enable loop vectorization on trees + ; -fverbose-asm causes extra commentary information to be produced in ; the generated assembly code (to make it more readable). This option ; is generally only of use to those who actually need to read the diff --git a/gcc/defaults.h b/gcc/defaults.h index ef8469c2dfa..04be1c9c370 100644 --- a/gcc/defaults.h +++ b/gcc/defaults.h @@ -674,6 +674,10 @@ You Lose! You must define PREFERRED_DEBUGGING_TYPE! #define VECTOR_MODE_SUPPORTED_P(MODE) 0 #endif +#ifndef UNITS_PER_SIMD_WORD +#define UNITS_PER_SIMD_WORD 0 +#endif + /* Determine whether __cxa_atexit, rather than atexit, is used to register C++ destructors for local statics and global objects. */ #ifndef DEFAULT_USE_CXA_ATEXIT diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index 98b66e29385..4eb1498ddca 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -263,7 +263,7 @@ Objective-C and Objective-C++ Dialects}. -fdump-tree-phiopt@r{[}-@var{n}@r{]} @gol -fdump-tree-forwprop@r{[}-@var{n}@r{]} @gol -fdump-tree-copyrename@r{[}-@var{n}@r{]} @gol --fdump-tree-nrv @gol +-fdump-tree-nrv -fdump-tree-vect @gol -fdump-tree-sra@r{[}-@var{n}@r{]} @gol -fdump-tree-fre@r{[}-@var{n}@r{]} @gol -feliminate-dwarf2-dups -feliminate-unused-debug-types @gol @@ -318,7 +318,7 @@ Objective-C and Objective-C++ Dialects}. -ftree-pre -ftree-ccp -ftree-dce -ftree-loop-optimize @gol -ftree-lim @gol -ftree-dominator-opts -ftree-dse -ftree-copyrename @gol --ftree-ch -ftree-sra -ftree-ter -ftree-lrs -ftree-fre @gol +-ftree-ch -ftree-sra -ftree-ter -ftree-lrs -ftree-fre -ftree-vectorize @gol --param @var{name}=@var{value} -O -O0 -O1 -O2 -O3 -Os} @@ -3664,6 +3664,11 @@ Dump each function after applying the named return value optimization on generic trees. The file name is made by appending @file{.nrv} to the source file name. +@item vect +@opindex fdump-tree-vect +Dump each function after applying vectorization of loops. The file name is +made by appending @file{.vect} to the source file name. + @item all @opindex fdump-tree-all Enable all the available tree dumps with the flags provided in this option. @@ -4499,6 +4504,9 @@ Perform live range splitting during the SSA->normal phase. Distinct live ranges of a variable are split into unique variables, allowing for better optimization later. This is enabled by default at -O and higher. +@item -ftree-vectorize +Perform loop vectorization on trees. + @item -ftracer @opindex ftracer Perform tail duplication to enlarge superblock size. This transformation diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 7ceee259881..64344815c7d 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2004-08-17 Dorit Naishlos + + * gcc.dg/vect: New directory for vectorizer tests. + (vect-*.c): New tests. + 2004-08-17 Paul Brook PR fortran/13082 diff --git a/gcc/testsuite/gcc.dg/vect/pr16105.c b/gcc/testsuite/gcc.dg/vect/pr16105.c new file mode 100644 index 00000000000..c75ab99bc8c --- /dev/null +++ b/gcc/testsuite/gcc.dg/vect/pr16105.c @@ -0,0 +1,22 @@ +/* { dg-do compile { target powerpc*-*-* i?86-*-* } } */ +/* { dg-options "-O2 -ftree-vectorize -fdump-tree-vect-stats -maltivec" { target powerpc*-*-* } } */ +/* { dg-options "-O2 -ftree-vectorize -fdump-tree-vect-stats -msse2" { target i?86-*-* } } */ + +#define VECTOR_SIZE 512 +typedef float afloat __attribute__ ((__aligned__(16))); + +extern void check(const afloat * __restrict__ v); + +void square(const afloat * __restrict__ a, + afloat * __restrict__ out) +{ + unsigned int i; + for (i = 0; i < VECTOR_SIZE; i++) { + float ai = a[i]; + float a2 = ai * ai; + out[i] = a2; + } + check(out); +} + +/* { dg-final { scan-tree-dump-times "vectorized 1 loops" 1 "vect"} } */ diff --git a/gcc/testsuite/gcc.dg/vect/tree-vect.h b/gcc/testsuite/gcc.dg/vect/tree-vect.h new file mode 100644 index 00000000000..c282e38cb9a --- /dev/null +++ b/gcc/testsuite/gcc.dg/vect/tree-vect.h @@ -0,0 +1,24 @@ +/* Check if system supports SIMD */ +#include + +extern void abort (void); +extern void exit (int); + +void +sig_ill_handler (int sig) +{ + exit(0); +} + +void check_vect (void) +{ + signal(SIGILL, sig_ill_handler); +#if defined(__ppc__) || defined(__ppc64__) + /* Altivec instruction, 'vor %v0,%v0,%v0'. */ + asm volatile (".long 0x10000484"); +#elif defined(__i386__) || defined(__x86_64__) + /* SSE2 instruction: movsd %xmm0,%xmm0 */ + asm volatile (".byte 0xf2,0x0f,0x10,0xc0"); +#endif + signal (SIGILL, SIG_DFL); +} diff --git a/gcc/testsuite/gcc.dg/vect/vect-1.c b/gcc/testsuite/gcc.dg/vect/vect-1.c new file mode 100644 index 00000000000..aa0b1f2f11c --- /dev/null +++ b/gcc/testsuite/gcc.dg/vect/vect-1.c @@ -0,0 +1,102 @@ +/* { dg-do compile { target powerpc*-*-* i?86-*-* x86_64-*-* } } */ +/* { dg-options "-O2 -ftree-vectorize -fdump-tree-vect-stats -maltivec" { target powerpc*-*-* } } */ +/* { dg-options "-O2 -ftree-vectorize -fdump-tree-vect-stats -msse2" { target i?86-*-* x86_64-*-* } } */ + +#define N 16 + +void fbar (float *); +void ibar (int *); +void sbar (short *); + +/* multiple loops */ + +foo (int n) +{ + float a[N+1]; + float b[N]; + float c[N]; + float d[N]; + int ia[N]; + int ib[N]; + int ic[N]; + short sa[N]; + short sb[N]; + short sc[N]; + int i,j; + int diff = 0; + char cb[N]; + char cc[N]; + char image[N][N]; + char block[N][N]; + + /* Not vetorizable yet (cross-iteration cycle). */ + diff = 0; + for (i = 0; i < N; i++) { + diff += (cb[i] - cc[i]); + } + ibar (&diff); + + + /* Not vetorizable yet (outer-loop: not attempted. + inner-loop: cross iteration cycle; multi-dimensional arrays). */ + diff = 0; + for (i = 0; i < N; i++) { + for (i = 0; i < N; i++) { + diff += (image[i][j] - block[i][j]); + } + } + ibar (&diff); + + + /* Vectorizable. */ + for (i = 0; i < N; i++){ + a[i] = b[i]; + } + fbar (a); + + + /* Vectorizable. */ + for (i = 0; i < N; i++){ + a[i] = b[i] + c[i] + d[i]; + } + fbar (a); + + + /* Not vetorizable yet (access pattern). */ + for (i = 0; i < N/2; i++){ + a[i] = b[2*i+1] * c[2*i+1] - b[2*i] * c[2*i]; + d[i] = b[2*i] * c[2*i+1] + b[2*i+1] * c[2*i]; + } + fbar (a); + + + /* Vectorizable. */ + for (i = 0; i < N; i++){ + a[i] = b[i] + c[i]; + d[i] = b[i] + c[i]; + ia[i] = ib[i] + ic[i]; + } + ibar (ia); + fbar (a); + fbar (d); + + + /* Not vectorizable yet (two types with different nunits in vector). */ + for (i = 0; i < N; i++){ + ia[i] = ib[i] + ic[i]; + sa[i] = sb[i] + sc[i]; + } + ibar (ia); + sbar (sa); + + + /* Not vetorizable yet (too conservative dependence test). */ + for (i = 0; i < N; i++){ + a[i] = b[i] + c[i]; + a[i+1] = b[i] + c[i]; + } + fbar (a); +} + +/* xfail: local arrays can't be aligned on a boundary greater than STACK_BOUNDARY */ +/* { dg-final { scan-tree-dump-times "vectorized 3 loops" 1 "vect" {xfail i?86-*-* x86_64-*-*} } } */ diff --git a/gcc/testsuite/gcc.dg/vect/vect-10.c b/gcc/testsuite/gcc.dg/vect/vect-10.c new file mode 100644 index 00000000000..b14f8eaa11e --- /dev/null +++ b/gcc/testsuite/gcc.dg/vect/vect-10.c @@ -0,0 +1,27 @@ +/* { dg-do compile { target powerpc*-*-* i?86-*-* x86_64-*-* } } */ +/* { dg-options "-O2 -ftree-vectorize -fdump-tree-vect-stats -maltivec" { target powerpc*-*-* } } */ +/* { dg-options "-O2 -ftree-vectorize -fdump-tree-vect-stats -msse2" { target i?86-*-* x86_64-*-* } } */ + +#define N 16 + +short a[N]; +short d[N]; + +int foo () +{ + int i; + short b[N] = {0,3,6,9,12,15,18,21,24,27,30,33,36,39,42,45}; + short c[N] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15}; + + + /* Not vetorizable yet (strided access pattern). */ + for (i = 0; i < N/2; i++) + { + a[i] = b[2*i+1] * c[2*i+1] - b[2*i] * c[2*i]; + d[i] = b[2*i] * c[2*i+1] + b[2*i+1] * c[2*i]; + } + + return 0; +} + +/* { dg-final { scan-tree-dump-times "vectorized 0 loops" 1 "vect" } } */ diff --git a/gcc/testsuite/gcc.dg/vect/vect-11.c b/gcc/testsuite/gcc.dg/vect/vect-11.c new file mode 100644 index 00000000000..cfcc642f913 --- /dev/null +++ b/gcc/testsuite/gcc.dg/vect/vect-11.c @@ -0,0 +1,41 @@ +/* { dg-do run { target powerpc*-*-* } } */ +/* { dg-do run { target i?86-*-* x86_64-*-* } } */ +/* { dg-options "-O2 -ftree-vectorize -fdump-tree-vect-stats -maltivec" { target powerpc*-*-* } } */ +/* { dg-options "-O2 -ftree-vectorize -fdump-tree-vect-stats -msse2" { target i?86-*-* x86_64-*-* } } */ + +#include +#include "tree-vect.h" + +#define N 16 + +int main1 () +{ + int i; + int ia[N]; + int ic[N] = {0,3,6,9,12,15,18,21,24,27,30,33,36,39,42,45}; + int ib[N] = {0,3,6,9,12,15,18,21,24,27,30,33,36,39,42,45}; + + /* Not vetorizable yet (integer mult). */ + for (i = 0; i < N; i++) + { + ia[i] = ib[i] * ic[i]; + } + + /* check results: */ + for (i = 0; i < N; i++) + { + if (ia[i] != ib[i] * ic[i]) + abort (); + } + + return 0; +} + +int main (void) +{ + check_vect (); + + return main1 (); +} + +/* { dg-final { scan-tree-dump-times "vectorized 1 loops" 0 "vect" } } */ diff --git a/gcc/testsuite/gcc.dg/vect/vect-12.c b/gcc/testsuite/gcc.dg/vect/vect-12.c new file mode 100644 index 00000000000..902a18a250b --- /dev/null +++ b/gcc/testsuite/gcc.dg/vect/vect-12.c @@ -0,0 +1,45 @@ +/* { dg-do run { target powerpc*-*-* } } */ +/* { dg-do run { target i?86-*-* x86_64-*-* } } */ +/* { dg-options "-O2 -ftree-vectorize -fdump-tree-vect-stats -maltivec" { target powerpc*-*-* } } */ +/* { dg-options "-O2 -ftree-vectorize -fdump-tree-vect-stats -msse2" { target i?86-*-* x86_64-*-* } } */ + +#include +#include "tree-vect.h" + +#define N 16 + +int main1 () +{ + int i; + int ia[N]; + int ic[N] = {0,3,6,9,12,15,18,21,24,27,30,33,36,39,42,45}; + int ib[N] = {0,3,6,9,12,15,18,21,24,27,30,33,36,39,42,45}; + short sa[N]; + short sc[N] = {0,3,6,9,12,15,18,21,24,27,30,33,36,39,42,45}; + short sb[N] = {0,3,6,9,12,15,18,21,24,27,30,33,36,39,42,45}; + + /* Not vetorizable yet (multiple types with different nunits in vector). */ + for (i = 0; i < N; i++) + { + ia[i] = ib[i] + ic[i]; + sa[i] = sb[i] + sc[i]; + } + + /* check results: */ + for (i = 0; i < N; i++) + { + if (ia[i] != ib[i] + ic[i] || sa[i] != sb[i] + sc[i]) + abort (); + } + + return 0; +} + +int main (void) +{ + check_vect (); + + return main1 (); +} + +/* { dg-final { scan-tree-dump-times "vectorized 1 loops" 1 "vect" { xfail *-*-* } } } */ diff --git a/gcc/testsuite/gcc.dg/vect/vect-13.c b/gcc/testsuite/gcc.dg/vect/vect-13.c new file mode 100644 index 00000000000..0a73a18ae7c --- /dev/null +++ b/gcc/testsuite/gcc.dg/vect/vect-13.c @@ -0,0 +1,25 @@ +/* { dg-do compile { target powerpc*-*-* i?86-*-* x86_64-*-* } } */ +/* { dg-options "-O2 -ftree-vectorize -fdump-tree-vect-stats -maltivec" { target powerpc*-*-* } } */ +/* { dg-options "-O2 -ftree-vectorize -fdump-tree-vect-stats -msse2" { target i?86-*-* x86_64-*-* } } */ + + +#define N 16 + +int a[N]; +int results[N] = {0,1,2,3,0,0,0,0,0,0,0,0,12,13,14,15}; + +int main () +{ + int i; + int b[N] = {0,1,2,3,-4,-5,-6,-7,-8,-9,-10,-11,12,13,14,15}; + + /* Not vectorizable yet (condition in loop). */ + for (i = 0; i < N; i++) + { + a[i] = (b[i] >= 0 ? b[i] : 0); + } + + return 0; +} + +/* { dg-final { scan-tree-dump-times "vectorized 1 loops" 1 "vect" { xfail *-*-* } } } */ diff --git a/gcc/testsuite/gcc.dg/vect/vect-14.c b/gcc/testsuite/gcc.dg/vect/vect-14.c new file mode 100644 index 00000000000..f6207c85c1c --- /dev/null +++ b/gcc/testsuite/gcc.dg/vect/vect-14.c @@ -0,0 +1,39 @@ +/* { dg-do run { target powerpc*-*-* } } */ +/* { dg-do run { target i?86-*-* x86_64-*-* } } */ +/* { dg-options "-O2 -ftree-vectorize -fdump-tree-vect-stats -maltivec" { target powerpc*-*-* } } */ +/* { dg-options "-O2 -ftree-vectorize -fdump-tree-vect-stats -msse2" { target i?86-*-* x86_64-*-* } } */ + +#include +#include "tree-vect.h" + +#define N 16 + +int main1 () +{ + int i; + int ia[N]; + + + /* Not vetorizable yet (induction). */ + for ( i = 0; i < N; i++) { + ia[i] = i; + } + + /* check results: */ + for (i = 0; i < N; i++) + { + if (ia[i] != i) + abort (); + } + + return 0; +} + +int main (void) +{ + check_vect(); + + return main1 (); +} + +/* { dg-final { scan-tree-dump-times "vectorized 1 loops" 1 "vect" { xfail *-*-* } } } */ diff --git a/gcc/testsuite/gcc.dg/vect/vect-15.c b/gcc/testsuite/gcc.dg/vect/vect-15.c new file mode 100644 index 00000000000..96c173dab16 --- /dev/null +++ b/gcc/testsuite/gcc.dg/vect/vect-15.c @@ -0,0 +1,40 @@ +/* { dg-do run { target powerpc*-*-* } } */ +/* { dg-do run { target i?86-*-* x86_64-*-* } } */ +/* { dg-options "-O2 -ftree-vectorize -fdump-tree-vect-stats -maltivec" { target powerpc*-*-* } } */ +/* { dg-options "-O2 -ftree-vectorize -fdump-tree-vect-stats -msse2" { target i?86-*-* x86_64-*-* } } */ + +#include +#include "tree-vect.h" + +#define N 16 + +int main1 () +{ + int i; + int a[N]; + int b[N] = {0,3,6,9,12,15,18,21,24,27,30,33,36,39,42,45}; + + /* Not vetorizable yet (reverse access and forward access). */ + for (i = N; i > 0; i--) + { + a[N-i] = b[i-1]; + } + + /* check results: */ + for (i = 0; i +#include "tree-vect.h" + +#define N 16 +#define DIFF 240 + +int main1 () +{ + int i; + float b[N] = {0,3,6,9,12,15,18,21,24,27,30,33,36,39,42,45}; + float c[N] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15}; + float diff; + + /* Not vetorizable yet (reduction). */ + diff = 0; + for (i = 0; i < N; i++) { + diff += (b[i] - c[i]); + } + + /* check results: */ + if (diff != DIFF) + abort (); + + return 0; +} + +int main (void) +{ + check_vect (); + + return main1 (); +} + +/* { dg-final { scan-tree-dump-times "vectorized 1 loops" 1 "vect" { xfail *-*-* } } } */ diff --git a/gcc/testsuite/gcc.dg/vect/vect-17.c b/gcc/testsuite/gcc.dg/vect/vect-17.c new file mode 100644 index 00000000000..bae19e0ad2c --- /dev/null +++ b/gcc/testsuite/gcc.dg/vect/vect-17.c @@ -0,0 +1,130 @@ +/* { dg-do run { target powerpc*-*-* } } */ +/* { dg-do run { target i?86-*-* x86_64-*-* } } */ +/* { dg-options "-O2 -ftree-vectorize -fdump-tree-vect-stats -maltivec" { target powerpc*-*-* } } */ +/* { dg-options "-O2 -ftree-vectorize -fdump-tree-vect-stats -msse2" { target i?86-*-* x86_64-*-* } } */ + +#include +#include "tree-vect.h" + +#define N 64 + +int +main1 () +{ + int i; + int ia[N]; + int ib[N]= + {1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0}; + + int ic[N] = + {1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0}; + + char ca[N]; + char cb[N] = + {1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0}; + + char cc[N] = + {1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0}; + + short sa[N]; + short sb[N] = + {1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0}; + + short sc[N] = + {1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0}; + + /* Check ints. */ + + for (i = 0; i < N; i++) + { + ia[i] = ib[i] & ic[i]; + } + + /* check results: */ + for (i = 0; i +#include "tree-vect.h" + +#define N 64 + +int +main1 () +{ + int i; + int ia[N]; + int ib[N]= + {1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0}; + int ic[N] = + {1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0}; + + char ca[N]; + char cb[N] = + {1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0}; + + char cc[N] = + {1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0}; + + short sa[N]; + short sb[N] = + {1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0}; + + short sc[N] = + {1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0}; + + /* Check ints. */ + + for (i = 0; i < N; i++) + { + ia[i] = (ib[i] | ic[i]); + } + + /* check results: */ + for (i = 0; i +#include "tree-vect.h" + +#define N 64 + +int +main1 () +{ + int i; + int ia[N]; + int ib[N]= + {1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0}; + int ic[N] = + {1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0}; + + char ca[N]; + char cb[N] = + {1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0}; + + char cc[N] = + {1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0}; + + short sa[N]; + short sb[N] = + {1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0}; + + short sc[N] = + {1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0}; + + /* Check ints. */ + + for (i = 0; i < N; i++) + { + ia[i] = ib[i] ^ ic[i]; + } + + /* check results: */ + for (i = 0; i +#include "tree-vect.h" + +#define N 16 + +int main1 () +{ + char cb[N] = {0,3,6,9,12,15,18,21,24,27,30,33,36,39,42,45}; + char ca[N]; + int i; + + for (i = 0; i < N; i++) + { + ca[i] = cb[i]; + } + + /* check results: */ + for (i = 0; i < N; i++) + { + if (ca[i] != cb[i]) + abort (); + } + + return 0; +} + +int main (void) +{ + check_vect (); + + return main1 (); +} + +/* xfail: local arrays can't be aligned on a boundary greater than STACK_BOUNDARY */ +/* { dg-final { scan-tree-dump-times "vectorized 1 loops" 1 "vect" {xfail i?86-*-* x86_64-*-*} } } */ diff --git a/gcc/testsuite/gcc.dg/vect/vect-20.c b/gcc/testsuite/gcc.dg/vect/vect-20.c new file mode 100644 index 00000000000..c5f4cef00dc --- /dev/null +++ b/gcc/testsuite/gcc.dg/vect/vect-20.c @@ -0,0 +1,129 @@ +/* { dg-do run { target powerpc*-*-* } } */ +/* { dg-do run { target i?86-*-* x86_64-*-* } } */ +/* { dg-options "-O2 -ftree-vectorize -fdump-tree-vect-stats -maltivec" { target powerpc*-*-* } } */ +/* { dg-options "-O2 -ftree-vectorize -fdump-tree-vect-stats -msse2" { target i?86-*-* x86_64-*-* } } */ + +#include +#include "tree-vect.h" + +#define N 64 + +int +main1 () +{ + int i; + int ia[N]; + int ib[N]= + {1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0}; + int ic[N] = + {1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0}; + + char ca[N]; + char cb[N] = + {1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0}; + + char cc[N] = + {1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0}; + + short sa[N]; + short sb[N] = + {1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0}; + + short sc[N] = + {1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0}; + + /* Check ints. */ + + for (i = 0; i < N; i++) + { + ia[i] = ~ib[i]; + } + + /* check results: */ + for (i = 0; i +#include "tree-vect.h" + +#define N 64 + +int +main1 () +{ + int i; + int ia[N]; + int ib[N]= + {1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0}; + int ic[N] = + {1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0}; + + char ca[N]; + char cb[N] = + {1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0}; + + char cc[N] = + {1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0}; + + short sa[N]; + short sb[N] = + {1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0}; + + short sc[N] = + {1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0}; + + /* Check ints. */ + + for (i = 0; i < N; i++) + { + ia[i] = !ib[i]; + } + + /* check results: */ + for (i = 0; i +#include "tree-vect.h" + +#define N 64 + +int +main1 () +{ + int i; + int ia[N]; + int ib[N]= + {1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0}; + int ic[N] = + {1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0}; + + char ca[N]; + char cb[N] = + {1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0}; + + char cc[N] = + {1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0}; + + short sa[N]; + short sb[N] = + {1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0}; + + short sc[N] = + {1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0}; + + /* Check ints. */ + + for (i = 0; i < N; i++) + { + ia[i] = -ib[i]; + } + + /* check results: */ + for (i = 0; i +#include "tree-vect.h" + +#define N 64 + +int +main1 () +{ + int i; + int ia[N]; + int ib[N]= + {1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0}; + int ic[N] = + {1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0}; + + char ca[N]; + char cb[N] = + {1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0}; + + char cc[N] = + {1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0}; + + short sa[N]; + short sb[N] = + {1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0}; + + short sc[N] = + {1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0}; + + /* Check ints. */ + + for (i = 0; i < N; i++) + { + ia[i] = ib[i] && ic[i]; + } + + /* check results: */ + for (i = 0; i +#include "tree-vect.h" + +#define N 64 + +int +main1 () +{ + int i; + int ia[N]; + int ib[N]= + {1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0}; + int ic[N] = + {1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0}; + + char ca[N]; + char cb[N] = + {1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0}; + + char cc[N] = + {1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0}; + + short sa[N]; + short sb[N] = + {1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0}; + + short sc[N] = + {1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0, + 1,1,0,0,1,0,1,0}; + + /* Check ints. */ + + for (i = 0; i < N; i++) + { + ia[i] = (ib[i] || ic[i]); + } + + /* check results: */ + for (i = 0; i +#include "tree-vect.h" + +#define N 128 + +int main1 (int n, int *p) +{ + int i; + int ib[N]; + int ia[N]; + int k; + + for (i = 0; i < N; i++) + { + ia[i] = n; + } + + /* check results: */ + for (i = 0; i < N; i++) + { + if (ia[i] != n) + abort (); + } + + k = *p; + for (i = 0; i < N; i++) + { + ib[i] = k; + } + + /* check results: */ + for (i = 0; i < N; i++) + { + if (ib[i] != k) + abort (); + } + + return 0; +} + +int main (void) +{ + int m = 8; + + check_vect (); + + return main1 (m, &m); +} + +/* xfail: local arrays can't be aligned on a boundary greater than STACK_BOUNDARY */ +/* { dg-final { scan-tree-dump-times "vectorized 2 loops" 1 "vect" {xfail i?86-*-* x86_64-*-*} } } */ diff --git a/gcc/testsuite/gcc.dg/vect/vect-26.c b/gcc/testsuite/gcc.dg/vect/vect-26.c new file mode 100644 index 00000000000..bfeb76ece69 --- /dev/null +++ b/gcc/testsuite/gcc.dg/vect/vect-26.c @@ -0,0 +1,41 @@ +/* { dg-do run { target powerpc*-*-* } } */ +/* { dg-do run { target i?86-*-* x86_64-*-* } } */ +/* { dg-options "-O2 -ftree-vectorize -fdump-tree-vect-stats -maltivec" { target powerpc*-*-* } } */ +/* { dg-options "-O2 -ftree-vectorize -fdump-tree-vect-stats -msse" { target i?86-*-* x86_64-*-* } } */ + +#include +#include "tree-vect.h" + +#define N 128 + +/* unaligned store. */ + +int main1 () +{ + int i; + int ia[N+1]; + + for (i = 1; i <= N; i++) + { + ia[i] = 5; + } + + /* check results: */ + for (i = 1; i <= N; i++) + { + if (ia[i] != 5) + abort (); + } + + return 0; +} + +int main (void) +{ + check_vect (); + + return main1 (); +} + +/* { dg-final { scan-tree-dump-times "vectorized 1 loops" 1 "vect" { xfail *-*-* } } } */ + diff --git a/gcc/testsuite/gcc.dg/vect/vect-27.c b/gcc/testsuite/gcc.dg/vect/vect-27.c new file mode 100644 index 00000000000..35e8f418f5f --- /dev/null +++ b/gcc/testsuite/gcc.dg/vect/vect-27.c @@ -0,0 +1,47 @@ +/* { dg-do run { target powerpc*-*-* } } */ +/* { dg-do run { target i?86-*-* x86_64-*-* } } */ +/* { dg-options "-O2 -ftree-vectorize -fdump-tree-vect-stats -maltivec" { target powerpc*-*-* } } */ +/* { dg-options "-O2 -ftree-vectorize -fdump-tree-vect-stats -msse" { target i?86-*-* x86_64-*-* } } */ + +#include +#include "tree-vect.h" + +#define N 128 + +/* unaligned load. */ + +int main1 () +{ + int i; + int ia[N]; + int ib[N+1]; + + for (i=0; i < N; i++) + { + ib[i] = i; + } + + for (i = 1; i <= N; i++) + { + ia[i-1] = ib[i]; + } + + /* check results: */ + for (i = 1; i <= N; i++) + { + if (ia[i-1] != ib[i]) + abort (); + } + + return 0; +} + +int main (void) +{ + check_vect (); + + return main1 (); +} + +/* { dg-final { scan-tree-dump-times "vectorized 1 loops" 1 "vect" { xfail *-*-* } } } */ + diff --git a/gcc/testsuite/gcc.dg/vect/vect-28.c b/gcc/testsuite/gcc.dg/vect/vect-28.c new file mode 100644 index 00000000000..b10cf136e17 --- /dev/null +++ b/gcc/testsuite/gcc.dg/vect/vect-28.c @@ -0,0 +1,44 @@ +/* { dg-do run { target powerpc*-*-* } } */ +/* { dg-do run { target i?86-*-* x86_64-*-* } } */ +/* { dg-options "-O2 -ftree-vectorize -fdump-tree-vect-stats -maltivec" { target powerpc*-*-* } } */ +/* { dg-options "-O2 -ftree-vectorize -fdump-tree-vect-stats -msse" { target i?86-*-* x86_64-*-* } } */ + +#include +#include "tree-vect.h" + +#define N 128 +#define OFF 3 + +/* unaligned store. */ + +int main1 (int off) +{ + int i; + int ia[N+OFF]; + + for (i = 0; i < N; i++) + { + ia[i+off] = 5; + } + + /* check results: */ + for (i = 0; i < N; i++) + { + if (ia[i+off] != 5) + abort (); + } + + return 0; +} + +int main (void) +{ + check_vect (); + + main1 (0); /* aligned */ + main1 (OFF); /* unaligned */ + return 0; +} + +/* { dg-final { scan-tree-dump-times "vectorized 1 loops" 1 "vect" { xfail *-*-* } } } */ + diff --git a/gcc/testsuite/gcc.dg/vect/vect-29.c b/gcc/testsuite/gcc.dg/vect/vect-29.c new file mode 100644 index 00000000000..80754f5fea5 --- /dev/null +++ b/gcc/testsuite/gcc.dg/vect/vect-29.c @@ -0,0 +1,50 @@ +/* { dg-do run { target powerpc*-*-* } } */ +/* { dg-do run { target i?86-*-* x86_64-*-* } } */ +/* { dg-options "-O2 -ftree-vectorize -fdump-tree-vect-stats -maltivec" { target powerpc*-*-* } } */ +/* { dg-options "-O2 -ftree-vectorize -fdump-tree-vect-stats -msse" { target i?86-*-* x86_64-*-* } } */ + +#include +#include "tree-vect.h" + +#define N 128 +#define OFF 3 + +/* unaligned load. */ + +int main1 (int off) +{ + int i; + int ia[N]; + int ib[N+OFF]; + + for (i = 0; i < N+OFF; i++) + { + ib[i] = i; + } + + for (i = 0; i < N; i++) + { + ia[i] = ib[i+off]; + } + + /* check results: */ + for (i = 0; i < N; i++) + { + if (ia[i] != ib[i+off]) + abort (); + } + + return 0; +} + +int main (void) +{ + check_vect (); + + main1 (0); /* aligned */ + main1 (OFF); /* unaligned */ + return 0; +} + +/* { dg-final { scan-tree-dump-times "vectorized 1 loops" 1 "vect" { xfail *-*-* } } } */ + diff --git a/gcc/testsuite/gcc.dg/vect/vect-3.c b/gcc/testsuite/gcc.dg/vect/vect-3.c new file mode 100644 index 00000000000..cd49a0d267d --- /dev/null +++ b/gcc/testsuite/gcc.dg/vect/vect-3.c @@ -0,0 +1,54 @@ +/* { dg-do run { target powerpc*-*-* } } */ +/* { dg-do run { target i?86-*-* x86_64-*-* } } */ +/* { dg-options "-O2 -ftree-vectorize -fdump-tree-vect-stats -maltivec" { target powerpc*-*-* } } */ +/* { dg-options "-O2 -ftree-vectorize -fdump-tree-vect-stats -msse2" { target i?86-*-* x86_64-*-* } } */ + +#include +#include "tree-vect.h" + +#define N 20 + +int +main1 () +{ + int i; + float a[N]; + float e[N]; + float b[N] = {0,3,6,9,12,15,18,21,24,27,30,33,36,39,42,45}; + float c[N] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15}; + float d[N] = {0,2,4,6,8,10,12,14,16,18,20,22,24,26,28,30}; + int ic[N] = {0,3,6,9,12,15,18,21,24,27,30,33,36,39,42,45}; + int ib[N] = {0,3,6,9,12,15,18,21,24,27,30,33,36,39,42,45}; + int ia[N]; + + for (i = 0; i < N; i++) + { + a[i] = b[i] + c[i] + d[i]; + e[i] = b[i] + c[i] + d[i]; + ia[i] = ib[i] + ic[i]; + } + + /* check results: */ + for (i = 0; i +#include "tree-vect.h" + +#define N 16 + +float b[N] = {0,2,4,6,8,10,12,14,16,18,20,22,24,26,28,30}; +float a[N]; +float c[N]; + +int main1 (int n) +{ + int i=0; + + /* Vectorized: unknown loop bound. */ + while (n--) { + a[i] = b[i]; + i++; + } + + /* check results: */ + for (i = 0; i < n; i++) + { + if (a[i] != b[i]) + abort (); + } + + return 0; +} + +int main2 (unsigned int n) +{ + int i=0; + int nn = n; + + /* Vectorized: unknown loop bound. */ + while (n--) { + c[i] = b[i]; + i++; + } + + /* check results: */ + for (i = 0; i < nn; i++) + { + if (c[i] != b[i]) + abort (); + } + + return 0; +} + +int main (void) +{ + check_vect (); + + main1 (N); + main2 (N); + return 0; +} + +/* { dg-final { scan-tree-dump-times "vectorized 1 loops" 2 "vect" { xfail *-*-* } } } */ diff --git a/gcc/testsuite/gcc.dg/vect/vect-31.c b/gcc/testsuite/gcc.dg/vect/vect-31.c new file mode 100644 index 00000000000..cb7f7cca42a --- /dev/null +++ b/gcc/testsuite/gcc.dg/vect/vect-31.c @@ -0,0 +1,92 @@ +/* { dg-do run { target powerpc*-*-* } } */ +/* { dg-do run { target i?86-*-* x86_64-*-* } } */ +/* { dg-options "-O2 -ftree-vectorize -fdump-tree-vect-stats -maltivec" { target powerpc*-*-* } } */ +/* { dg-options "-O2 -ftree-vectorize -fdump-tree-vect-stats -msse2" { target i?86-*-* x86_64-*-* } } */ + +#include +#include "tree-vect.h" + +#define N 32 + +struct t{ + int k[N]; + int l; +}; + +struct s{ + char a; /* aligned */ + char b[N-1]; /* unaligned (offset 1B) */ + char c[N]; /* aligned (offset NB) */ + struct t d; /* aligned (offset 2NB) */ + struct t e; /* unaligned (offset 2N+4N+4 B) */ +}; + +int main1 () +{ + int i; + struct s tmp; + + /* unaligned */ + for (i = 0; i < N/2; i++) + { + tmp.b[i] = 5; + } + + /* check results: */ + for (i = 0; i +#include "tree-vect.h" + +#define N 16 + +int main1 () +{ + struct { + char ca[N]; + } s; + int i; + + for (i = 0; i < N; i++) + { + s.ca[i] = 5; + } + + /* check results: */ + for (i = 0; i < N; i++) + { + if (s.ca[i] != 5) + abort (); + } + + return 0; +} + +int main (void) +{ + check_vect (); + + return main1 (); +} + +/* xfail: local arrays can't be aligned on a boundary greater than STACK_BOUNDARY */ +/* { dg-final { scan-tree-dump-times "vectorized 1 loops" 1 "vect" {xfail i?86-*-* x86_64-*-*} } } */ diff --git a/gcc/testsuite/gcc.dg/vect/vect-33.c b/gcc/testsuite/gcc.dg/vect/vect-33.c new file mode 100644 index 00000000000..137e6982124 --- /dev/null +++ b/gcc/testsuite/gcc.dg/vect/vect-33.c @@ -0,0 +1,41 @@ +/* { dg-do compile { target powerpc*-*-* } } */ +/* { dg-do compile { target i?86-*-* x86_64-*-* } } */ +/* { dg-options "-S -O2 -ftree-vectorize -fdump-tree-vect-stats -maltivec" { target powerpc*-*-* } } */ +/* { dg-options "-S -O2 -ftree-vectorize -fdump-tree-vect-stats -msse2" { target i?86-*-* x86_64-*-* } } */ + +#include +#include "tree-vect.h" + +#define N 16 +struct test { + char ca[N]; +}; + +extern struct test s; + +int main1 () +{ + int i; + + for (i = 0; i < N; i++) + { + s.ca[i] = 5; + } + + /* check results: */ + for (i = 0; i < N; i++) + { + if (s.ca[i] != 5) + abort (); + } + + return 0; +} + +int main (void) +{ + return main1 (); +} + + +/* { dg-final { scan-tree-dump-times "vectorized 1 loops" 1 "vect" { xfail *-*-* } } } */ diff --git a/gcc/testsuite/gcc.dg/vect/vect-34.c b/gcc/testsuite/gcc.dg/vect/vect-34.c new file mode 100644 index 00000000000..7adbf689eaf --- /dev/null +++ b/gcc/testsuite/gcc.dg/vect/vect-34.c @@ -0,0 +1,42 @@ +/* { dg-do run { target powerpc*-*-* } } */ +/* { dg-do run { target i?86-*-* x86_64-*-* } } */ +/* { dg-options "-O2 -ftree-vectorize -fdump-tree-vect-stats -maltivec" { target powerpc*-*-* } } */ +/* { dg-options "-O2 -ftree-vectorize -fdump-tree-vect-stats -msse2" { target i?86-*-* x86_64-*-* } } */ + +#include +#include "tree-vect.h" + +#define N 16 + +int main1 () +{ + struct { + char ca[N]; + } s; + char cb[N] = {0,3,6,9,12,15,18,21,24,27,30,33,36,39,42,45}; + int i; + + for (i = 0; i < N; i++) + { + s.ca[i] = cb[i]; + } + + /* check results: */ + for (i = 0; i < N; i++) + { + if (s.ca[i] != cb[i]) + abort (); + } + + return 0; +} + +int main (void) +{ + check_vect (); + + return main1 (); +} + +/* xfail: local arrays can't be aligned on a boundary greater than STACK_BOUNDARY */ +/* { dg-final { scan-tree-dump-times "vectorized 1 loops" 1 "vect" {xfail i?86-*-* x86_64-*-*} } } */ diff --git a/gcc/testsuite/gcc.dg/vect/vect-35.c b/gcc/testsuite/gcc.dg/vect/vect-35.c new file mode 100644 index 00000000000..b29da494942 --- /dev/null +++ b/gcc/testsuite/gcc.dg/vect/vect-35.c @@ -0,0 +1,50 @@ +/* { dg-do run { target powerpc*-*-* } } */ +/* { dg-do run { target i?86-*-* x86_64-*-* } } */ +/* { dg-options "-O2 -ftree-vectorize -fdump-tree-vect-stats -maltivec" { target powerpc*-*-* } } */ +/* { dg-options "-O2 -ftree-vectorize -fdump-tree-vect-stats -msse2" { target i?86-*-* x86_64-*-* } } */ + +#include +#include "tree-vect.h" + +typedef char achar __attribute__ ((__aligned__(16))); + +#define N 16 +achar x[N]; + +int main1 () +{ + union { + achar a[N]; + achar b[N]; + } s; + int i; + + for (i = 0; i < N; i++) + { + s.b[i] = 3*i; + } + + for (i = 0; i < N; i++) + { + s.a[i] = s.b[i] + 1; + } + + /* check results: */ + for (i = 0; i < N; i++) + { + if (s.a[i] != s.b[i]) + abort (); + } + + return 0; +} + +int main (void) +{ + check_vect (); + + return main1 (); +} + + +/* { dg-final { scan-tree-dump-times "vectorized 0 loops" 1 "vect" } } */ diff --git a/gcc/testsuite/gcc.dg/vect/vect-36.c b/gcc/testsuite/gcc.dg/vect/vect-36.c new file mode 100644 index 00000000000..b3c60d9ef13 --- /dev/null +++ b/gcc/testsuite/gcc.dg/vect/vect-36.c @@ -0,0 +1,47 @@ +/* { dg-do run { target powerpc*-*-* } } */ +/* { dg-do run { target i?86-*-* x86_64-*-* } } */ +/* { dg-options "-O2 -ftree-vectorize -fdump-tree-vect-stats -maltivec" { target powerpc*-*-* } } */ +/* { dg-options "-O2 -ftree-vectorize -fdump-tree-vect-stats -msse2" { target i?86-*-* x86_64-*-* } } */ + +#include +#include "tree-vect.h" + +#define N 16 + +int main1 () +{ + struct { + char ca[N]; + char cb[N]; + } s; + int i; + + for (i = 0; i < N; i++) + { + s.cb[i] = 3*i; + } + + for (i = 0; i < N; i++) + { + s.ca[i] = s.cb[i]; + } + + /* check results: */ + for (i = 0; i < N; i++) + { + if (s.ca[i] != s.cb[i]) + abort (); + } + + return 0; +} + +int main (void) +{ + check_vect (); + + return main1 (); +} + +/* xfail: local arrays can't be aligned on a boundary greater than STACK_BOUNDARY */ +/* { dg-final { scan-tree-dump-times "vectorized 1 loops" 1 "vect" {xfail i?86-*-* x86_64-*-*} } } */ diff --git a/gcc/testsuite/gcc.dg/vect/vect-37.c b/gcc/testsuite/gcc.dg/vect/vect-37.c new file mode 100644 index 00000000000..97f31106602 --- /dev/null +++ b/gcc/testsuite/gcc.dg/vect/vect-37.c @@ -0,0 +1,61 @@ +/* { dg-do run { target powerpc*-*-* } } */ +/* { dg-do run { target i?86-*-* x86_64-*-* } } */ +/* { dg-options "-O2 -ftree-vectorize -fdump-tree-vect-stats -maltivec" { target powerpc*-*-* } } */ +/* { dg-options "-O2 -ftree-vectorize -fdump-tree-vect-stats -msse2" { target i?86-*-* x86_64-*-* } } */ + +#include +#include "tree-vect.h" + +typedef char achar __attribute__ ((__aligned__(16))); + +#define N 16 +achar x[N]; + +int main1 (achar *y) +{ + struct { + achar *p; + achar *q; + } s; + achar cb[N] = {0,3,6,9,12,15,18,21,24,27,30,33,36,39,42,45}; + int i; + + s.p = y; + for (i = 0; i < N; i++) + { + s.p[i] = cb[i]; + } + + /* check results: */ + for (i = 0; i < N; i++) + { + if (s.p[i] != cb[i]) + abort (); + } + + s.q = cb; + for (i = 0; i < N; i++) + { + s.p[i] = s.q[i]; + } + + /* check results: */ + for (i = 0; i < N; i++) + { + if (s.p[i] != s.q[i]) + abort (); + } + + return 0; +} + +int main (void) +{ + check_vect (); + + return main1 (x); +} + + +/* { dg-final { scan-tree-dump-times "vectorized 0 loops" 1 "vect" } } */ +/* { dg-final { scan-tree-dump-times "vectorized 2 loops" 1 "vect" { xfail *-*-* } } } */ diff --git a/gcc/testsuite/gcc.dg/vect/vect-38.c b/gcc/testsuite/gcc.dg/vect/vect-38.c new file mode 100644 index 00000000000..df2cf9c2c5d --- /dev/null +++ b/gcc/testsuite/gcc.dg/vect/vect-38.c @@ -0,0 +1,41 @@ +/* { dg-do run { target powerpc*-*-* } } */ +/* { dg-do run { target i?86-*-* x86_64-*-* } } */ +/* { dg-options "-O2 -ftree-vectorize -fdump-tree-vect-stats -maltivec" { target powerpc*-*-* } } */ +/* { dg-options "-O2 -ftree-vectorize -fdump-tree-vect-stats -msse2" { target i?86-*-* x86_64-*-* } } */ + +#include +#include "tree-vect.h" + +#define N 16 + +double cb[N] = {0,3,6,9,12,15,18,21,24,27,30,33,36,39,42,45}; +double ca[N]; + +int main1 () +{ + int i; + + for (i = 0; i < N; i++) + { + ca[i] = cb[i]; + } + + /* check results: */ + for (i = 0; i < N; i++) + { + if (ca[i] != cb[i]) + abort (); + } + + return 0; +} + +int main (void) +{ + check_vect (); + + return main1 (); +} + + +/* { dg-final { scan-tree-dump-times "vectorized 1 loops" 1 "vect" { xfail powerpc*-*-* } } } */ diff --git a/gcc/testsuite/gcc.dg/vect/vect-4.c b/gcc/testsuite/gcc.dg/vect/vect-4.c new file mode 100644 index 00000000000..943d71f2047 --- /dev/null +++ b/gcc/testsuite/gcc.dg/vect/vect-4.c @@ -0,0 +1,42 @@ +/* { dg-do run { target powerpc*-*-* } } */ +/* { dg-do run { target i?86-*-* x86_64-*-* } } */ +/* { dg-options "-O2 -ftree-vectorize -fdump-tree-vect-stats -maltivec" { target powerpc*-*-* } } */ +/* { dg-options "-O2 -ftree-vectorize -fdump-tree-vect-stats -msse2" { target i?86-*-* x86_64-*-* } } */ + +#include +#include "tree-vect.h" + +#define N 20 + +int +main1 () +{ + int i; + float a[N]; + float b[N] = {0,3,6,9,12,15,18,21,24,27,30,33,36,39,42,45,48,51,54,57}; + float c[N] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19}; + + for (i = 0; i < N; i++) + { + a[i] = b[i] * c[i]; + } + + /* check results: */ + for (i = 0; i +#include "tree-vect.h" + +#define N 256 + +typedef float afloat __attribute__ ((__aligned__(16))); + +void bar (afloat *pa, afloat *pb, afloat *pc) +{ + int i; + + /* check results: */ + for (i = 0; i < N; i++) + { + if (pa[i] != (pb[i] * pc[i])) + abort (); + } + + return; +} + + +int +main1 (afloat * __restrict__ pa, afloat * __restrict__ pb, afloat * __restrict__ pc) +{ + int i; + + for (i = 0; i < N; i++) + { + pa[i] = pb[i] * pc[i]; + } + + return 0; +} + +int main (void) +{ + int i; + afloat a[N]; + afloat b[N] = {0,3,6,9,12,15,18,21,24,27,30,33,36,39,42,45,48,51,54,57}; + afloat c[N] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19}; + + check_vect (); + + main1 (a,b,c); + bar (a,b,c); + return 0; +} + +/* { dg-final { scan-tree-dump-times "vectorized 1 loops" 1 "vect"} } */ diff --git a/gcc/testsuite/gcc.dg/vect/vect-41.c b/gcc/testsuite/gcc.dg/vect/vect-41.c new file mode 100644 index 00000000000..0f9cae4ee8f --- /dev/null +++ b/gcc/testsuite/gcc.dg/vect/vect-41.c @@ -0,0 +1,56 @@ +/* { dg-do run { target powerpc*-*-* } } */ +/* { dg-do run { target i?86-*-* x86_64-*-* } } */ +/* { dg-options "-O2 -ftree-vectorize -fdump-tree-vect-stats -maltivec" { target powerpc*-*-* } } */ +/* { dg-options "-O2 -ftree-vectorize -fdump-tree-vect-stats -msse" { target i?86-*-* x86_64-*-* } } */ + +#include +#include "tree-vect.h" + +#define N 256 + +typedef float afloat __attribute__ ((__aligned__(16))); + +void bar (afloat *pa, afloat *pb, afloat *pc) +{ + int i; + + /* check results: */ + for (i = 0; i < N; i++) + { + if (pa[i] != (pb[i] * pc[i])) + abort (); + } + + return; +} + + +int +main1 (afloat * pa, afloat * pb, afloat * pc) +{ + int i; + + for (i = 0; i < N; i++) + { + pa[i] = pb[i] * pc[i]; + } + + bar (pa,pb,pc); + + return 0; +} + +int main (void) +{ + int i; + afloat a[N]; + afloat b[N] = {0,3,6,9,12,15,18,21,24,27,30,33,36,39,42,45,48,51,54,57}; + afloat c[N] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19}; + + check_vect (); + + main1 (a,b,c); + return 0; +} + +/* { dg-final { scan-tree-dump-times "vectorized 1 loops" 1 "vect" { xfail *-*-* } } } */ diff --git a/gcc/testsuite/gcc.dg/vect/vect-42.c b/gcc/testsuite/gcc.dg/vect/vect-42.c new file mode 100644 index 00000000000..7f79d42de49 --- /dev/null +++ b/gcc/testsuite/gcc.dg/vect/vect-42.c @@ -0,0 +1,58 @@ +/* { dg-do run { target powerpc*-*-* } } */ +/* { dg-do run { target i?86-*-* x86_64-*-* } } */ +/* { dg-options "-O2 -ftree-vectorize -fdump-tree-vect-stats -maltivec" { target powerpc*-*-* } } */ +/* { dg-options "-O2 -ftree-vectorize -fdump-tree-vect-stats -msse" { target i?86-*-* x86_64-*-* } } */ + +#include +#include "tree-vect.h" + +#define N 256 + +typedef float afloat __attribute__ ((__aligned__(16))); + +void bar (afloat *pa, afloat *pb, afloat *pc) +{ + int i; + + /* check results: */ + for (i = 0; i < N; i++) + { + if (pa[i] != (pb[i] * pc[i])) + abort (); + } + + return; +} + + +int +main1 (afloat * __restrict__ 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}; + + + for (i = 0; i < N; i++) + { + pa[i] = pb[i] * pc[i]; + } + + return 0; +} + +int main (void) +{ + int i; + afloat a[N]; + afloat b[N] = {0,3,6,9,12,15,18,21,24,27,30,33,36,39,42,45,48,51,54,57}; + afloat c[N] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19}; + + check_vect (); + + main1 (a); + bar (a,b,c); + return 0; +} + +/* { dg-final { scan-tree-dump-times "vectorized 1 loops" 1 "vect"} } */ diff --git a/gcc/testsuite/gcc.dg/vect/vect-43.c b/gcc/testsuite/gcc.dg/vect/vect-43.c new file mode 100644 index 00000000000..370b5dd8bb7 --- /dev/null +++ b/gcc/testsuite/gcc.dg/vect/vect-43.c @@ -0,0 +1,59 @@ +/* { dg-do run { target powerpc*-*-* } } */ +/* { dg-do run { target i?86-*-* x86_64-*-* } } */ +/* { dg-options "-O2 -ftree-vectorize -fdump-tree-vect-stats -maltivec" { target powerpc*-*-* } } */ +/* { dg-options "-O2 -ftree-vectorize -fdump-tree-vect-stats -msse" { target i?86-*-* x86_64-*-* } } */ + +#include +#include "tree-vect.h" + +#define N 256 + +typedef float afloat __attribute__ ((__aligned__(16))); + +void bar (afloat *pa, afloat *pb, afloat *pc) +{ + int i; + + /* check results: */ + for (i = 0; i < N; i++) + { + if (pa[i] != (pb[i] * pc[i])) + abort (); + } + + return; +} + + +int +main1 (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}; + + + for (i = 0; i < N; i++) + { + pa[i] = pb[i] * pc[i]; + } + + bar (pa,pb,pc); + + return 0; +} + +int main (void) +{ + int i; + afloat a[N]; + afloat b[N] = {0,3,6,9,12,15,18,21,24,27,30,33,36,39,42,45,48,51,54,57}; + afloat c[N] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19}; + + check_vect (); + + main1 (a); + return 0; +} + +/* { dg-final { scan-tree-dump-times "vectorized 1 loops" 1 "vect" } } */ diff --git a/gcc/testsuite/gcc.dg/vect/vect-44.c b/gcc/testsuite/gcc.dg/vect/vect-44.c new file mode 100644 index 00000000000..4068ab1d577 --- /dev/null +++ b/gcc/testsuite/gcc.dg/vect/vect-44.c @@ -0,0 +1,55 @@ +/* { dg-do run { target powerpc*-*-* } } */ +/* { dg-do run { target i?86-*-* x86_64-*-* } } */ +/* { dg-options "-O2 -ftree-vectorize -fdump-tree-vect-stats -maltivec" { target powerpc*-*-* } } */ +/* { dg-options "-O2 -ftree-vectorize -fdump-tree-vect-stats -msse" { target i?86-*-* x86_64-*-* } } */ + +#include +#include "tree-vect.h" + +#define N 256 + + +void bar (float *pa, float *pb, float *pc) +{ + int i; + + /* check results: */ + for (i = 0; i < N; i++) + { + if (pa[i] != (pb[i] * pc[i])) + abort (); + } + + return; +} + + +int +main1 (float * __restrict__ pa, float * __restrict__ pb, float * __restrict__ pc) +{ + int i; + + for (i = 0; i < N; i++) + { + pa[i] = pb[i] * pc[i]; + } + + bar (pa,pb,pc); + + return 0; +} + +int main (void) +{ + int i; + float a[N]; + float b[N] = {0,3,6,9,12,15,18,21,24,27,30,33,36,39,42,45,48,51,54,57}; + float c[N] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19}; + + check_vect (); + + main1 (a,b,c); + return 0; +} + +/* { dg-final { scan-tree-dump-times "vectorized 1 loops" 1 "vect" { xfail *-*-* } } } */ diff --git a/gcc/testsuite/gcc.dg/vect/vect-45.c b/gcc/testsuite/gcc.dg/vect/vect-45.c new file mode 100644 index 00000000000..c0b0029e12f --- /dev/null +++ b/gcc/testsuite/gcc.dg/vect/vect-45.c @@ -0,0 +1,55 @@ +/* { dg-do run { target powerpc*-*-* } } */ +/* { dg-do run { target i?86-*-* x86_64-*-* } } */ +/* { dg-options "-O2 -ftree-vectorize -fdump-tree-vect-stats -maltivec" { target powerpc*-*-* } } */ +/* { dg-options "-O2 -ftree-vectorize -fdump-tree-vect-stats -msse" { target i?86-*-* x86_64-*-* } } */ + +#include +#include "tree-vect.h" + +#define N 256 + + +void bar (const float *pa, const float *pb, const float *pc) +{ + int i; + + /* check results: */ + for (i = 0; i < N; i++) + { + if (pa[i] != (pb[i] * pc[i])) + abort (); + } + + return; +} + + +int +main1 (float *pa, float *pb, float *pc) +{ + int i; + + for (i = 0; i < N; i++) + { + pa[i] = pb[i] * pc[i]; + } + + bar (pa,pb,pc); + + return 0; +} + +int main (void) +{ + int i; + float a[N]; + float b[N] = {0,3,6,9,12,15,18,21,24,27,30,33,36,39,42,45,48,51,54,57}; + float c[N] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19}; + + check_vect (); + + main1 (a,b,c); + return 0; +} + +/* { dg-final { scan-tree-dump-times "vectorized 1 loops" 1 "vect" { xfail *-*-* } } } */ diff --git a/gcc/testsuite/gcc.dg/vect/vect-46.c b/gcc/testsuite/gcc.dg/vect/vect-46.c new file mode 100644 index 00000000000..1fb08a7eab5 --- /dev/null +++ b/gcc/testsuite/gcc.dg/vect/vect-46.c @@ -0,0 +1,56 @@ +/* { dg-do run { target powerpc*-*-* } } */ +/* { dg-do run { target i?86-*-* x86_64-*-* } } */ +/* { dg-options "-O2 -ftree-vectorize -fdump-tree-vect-stats -maltivec" { target powerpc*-*-* } } */ +/* { dg-options "-O2 -ftree-vectorize -fdump-tree-vect-stats -msse" { target i?86-*-* x86_64-*-* } } */ + +#include +#include "tree-vect.h" + +#define N 256 + +typedef float afloat __attribute__ ((__aligned__(16))); + +void bar (afloat *pa, afloat *pb, afloat *pc) +{ + int i; + + /* check results: */ + for (i = 0; i < N; i++) + { + if (pa[i] != (pb[i] * pc[i])) + abort(); + } + + return; +} + + +int +main1 (int n , afloat * __restrict__ pa, afloat * __restrict__ pb, afloat * __restrict__ pc) +{ + int i; + + for (i = 0; i < n; i++) + { + pa[i] = pb[i] * pc[i]; + } + + return 0; +} + +int main (void) +{ + int i; + int n=N; + afloat a[N]; + afloat b[N] = {0,3,6,9,12,15,18,21,24,27,30,33,36,39,42,45,48,51,54,57}; + afloat c[N] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19}; + + check_vect (); + + main1 (n,a,b,c); + bar (a,b,c); + return 0; +} + +/* { dg-final { scan-tree-dump-times "vectorized 1 loops" 1 "vect" { xfail *-*-* } } } */ diff --git a/gcc/testsuite/gcc.dg/vect/vect-47.c b/gcc/testsuite/gcc.dg/vect/vect-47.c new file mode 100644 index 00000000000..e1e1d38e6b6 --- /dev/null +++ b/gcc/testsuite/gcc.dg/vect/vect-47.c @@ -0,0 +1,57 @@ +/* { dg-do run { target powerpc*-*-* } } */ +/* { dg-do run { target i?86-*-* x86_64-*-* } } */ +/* { dg-options "-O2 -ftree-vectorize -fdump-tree-vect-stats -maltivec" { target powerpc*-*-* } } */ +/* { dg-options "-O2 -ftree-vectorize -fdump-tree-vect-stats -msse" { target i?86-*-* x86_64-*-* } } */ + +#include +#include "tree-vect.h" + +#define N 256 + +typedef float afloat __attribute__ ((__aligned__(16))); + +void bar (afloat *pa, afloat *pb, afloat *pc) +{ + int i; + + /* check results: */ + for (i = 0; i < N; i++) + { + if (pa[i] != (pb[i] * pc[i])) + abort (); + } + + return; +} + + +int +main1 (int n , afloat * pa, afloat * pb, afloat * pc) +{ + int i; + + for (i = 0; i < n; i++) + { + pa[i] = pb[i] * pc[i]; + } + + bar (pa,pb,pc); + + return 0; +} + +int main (void) +{ + int i; + int n=N; + afloat a[N]; + afloat b[N] = {0,3,6,9,12,15,18,21,24,27,30,33,36,39,42,45,48,51,54,57}; + afloat c[N] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19}; + + check_vect (); + + main1 (n,a,b,c); + return 0; +} + +/* { dg-final { scan-tree-dump-times "vectorized 1 loops" 1 "vect" { xfail *-*-* } } } */ diff --git a/gcc/testsuite/gcc.dg/vect/vect-48.c b/gcc/testsuite/gcc.dg/vect/vect-48.c new file mode 100644 index 00000000000..c7485be3a0b --- /dev/null +++ b/gcc/testsuite/gcc.dg/vect/vect-48.c @@ -0,0 +1,56 @@ +/* { dg-do run { target powerpc*-*-* } } */ +/* { dg-do run { target i?86-*-* x86_64-*-* } } */ +/* { dg-options "-O2 -ftree-vectorize -fdump-tree-vect-stats -maltivec" { target powerpc*-*-* } } */ +/* { dg-options "-O2 -ftree-vectorize -fdump-tree-vect-stats -msse" { target i?86-*-* x86_64-*-* } } */ + +#include +#include "tree-vect.h" + +#define N 256 + +typedef float afloat __attribute__ ((__aligned__(16))); + +void bar (float *pa, float *pb, float *pc) +{ + int i; + + /* check results: */ + for (i = 0; i < N; i++) + { + if (pa[i] != (pb[i] * pc[i])) + abort (); + } + + return; +} + + +int +main1 (afloat * __restrict__ pa, float * __restrict__ pb, float * __restrict__ pc) +{ + int i; + + for (i = 0; i < N; i++) + { + pa[i] = pb[i] * pc[i]; + } + + bar (pa,pb,pc); + + return 0; +} + +int main (void) +{ + int i; + float a[N]; + float b[N] = {0,3,6,9,12,15,18,21,24,27,30,33,36,39,42,45,48,51,54,57}; + float c[N] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19}; + + check_vect (); + + main1 (a,b,c); + return 0; +} + +/* { dg-final { scan-tree-dump-times "vectorized 1 loops" 1 "vect" { xfail *-*-* } } } */ diff --git a/gcc/testsuite/gcc.dg/vect/vect-49.c b/gcc/testsuite/gcc.dg/vect/vect-49.c new file mode 100644 index 00000000000..8d8b212a66f --- /dev/null +++ b/gcc/testsuite/gcc.dg/vect/vect-49.c @@ -0,0 +1,56 @@ +/* { dg-do run { target powerpc*-*-* } } */ +/* { dg-do run { target i?86-*-* x86_64-*-* } } */ +/* { dg-options "-O2 -ftree-vectorize -fdump-tree-vect-stats -maltivec" { target powerpc*-*-* } } */ +/* { dg-options "-O2 -ftree-vectorize -fdump-tree-vect-stats -msse" { target i?86-*-* x86_64-*-* } } */ + +#include +#include "tree-vect.h" + +#define N 256 + +typedef float afloat __attribute__ ((__aligned__(16))); + +void bar (const float *pa, const float *pb, const float *pc) +{ + int i; + + /* check results: */ + for (i = 0; i < N; i++) + { + if (pa[i] != (pb[i] * pc[i])) + abort (); + } + + return; +} + + +int +main1 (afloat *pa, float *pb, float *pc) +{ + int i; + + for (i = 0; i < N; i++) + { + pa[i] = pb[i] * pc[i]; + } + + bar (pa,pb,pc); + + return 0; +} + +int main (void) +{ + int i; + float a[N]; + float b[N] = {0,3,6,9,12,15,18,21,24,27,30,33,36,39,42,45,48,51,54,57}; + float c[N] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19}; + + check_vect (); + + main1 (a,b,c); + return 0; +} + +/* { dg-final { scan-tree-dump-times "vectorized 1 loops" 1 "vect" { xfail *-*-* } } } */ diff --git a/gcc/testsuite/gcc.dg/vect/vect-5.c b/gcc/testsuite/gcc.dg/vect/vect-5.c new file mode 100644 index 00000000000..bab9e23d491 --- /dev/null +++ b/gcc/testsuite/gcc.dg/vect/vect-5.c @@ -0,0 +1,58 @@ +/* { dg-do run { target powerpc*-*-* } } */ +/* { dg-do run { target i?86-*-* x86_64-*-* } } */ +/* { dg-options "-O2 -ftree-vectorize -fdump-tree-vect-stats -maltivec" { target powerpc*-*-* } } */ +/* { dg-options "-O2 -ftree-vectorize -fdump-tree-vect-stats -msse2" { target i?86-*-* x86_64-*-* } } */ + +#include +#include "tree-vect.h" + +#define N 16 + +int main1 () +{ + int i, j; + float a[N]; + float c[N] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15}; + float d[N] = {0,2,4,6,8,10,12,14,16,18,20,22,24,26,28,30}; + + i = 0; + j = 0; + while (i < 5*N) + { + a[j] = c[j]; + i += 5; + j++; + } + + /* check results: */ + for (i = 0; i 0; i--) + { + a[N-i] = d[N-i]; + } + + /* check results: */ + for (i = 0; i < N; i++) + { + if (a[i] != d[i]) + abort (); + } + + return 0; +} + +int main (void) +{ + check_vect (); + + return main1 (); +} + +/* xfail: local arrays can't be aligned on a boundary greater than STACK_BOUNDARY */ +/* { dg-final { scan-tree-dump-times "vectorized 2 loops" 1 "vect" {xfail i?86-*-* x86_64-*-*} } } */ diff --git a/gcc/testsuite/gcc.dg/vect/vect-50.c b/gcc/testsuite/gcc.dg/vect/vect-50.c new file mode 100644 index 00000000000..cd7cf5d4996 --- /dev/null +++ b/gcc/testsuite/gcc.dg/vect/vect-50.c @@ -0,0 +1,54 @@ +/* { dg-do run { target powerpc*-*-* } } */ +/* { dg-do run { target i?86-*-* x86_64-*-* } } */ +/* { dg-options "-O2 -ftree-vectorize -fdump-tree-vect-stats -maltivec" { target powerpc*-*-* } } */ +/* { dg-options "-O2 -ftree-vectorize -fdump-tree-vect-stats -msse" { target i?86-*-* x86_64-*-* } } */ + +#include +#include "tree-vect.h" + +#define N 256 + + +void bar (float *pa, float *pb, float *pc) +{ + int i; + + /* check results: */ + for (i = 0; i < N; i++) + { + if (pa[i] != (pb[i] * pc[i])) + abort (); + } + + return; +} + + +int +main1 (int n, float * __restrict__ pa, float * __restrict__ pb, float * __restrict__ pc) +{ + int i; + + for (i = 0; i < n; i++) + { + pa[i] = pb[i] * pc[i]; + } + + bar (pa,pb,pc); + + return 0; +} + +int main (void) +{ + int i; + float a[N]; + float b[N] = {0,3,6,9,12,15,18,21,24,27,30,33,36,39,42,45,48,51,54,57}; + float c[N] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19}; + + check_vect (); + + main1 (N,a,b,c); +} + +/* { dg-final { scan-tree-dump-times "vectorized 1 loops" 1 "vect" { xfail *-*-* } } } */ diff --git a/gcc/testsuite/gcc.dg/vect/vect-51.c b/gcc/testsuite/gcc.dg/vect/vect-51.c new file mode 100644 index 00000000000..65c0f402754 --- /dev/null +++ b/gcc/testsuite/gcc.dg/vect/vect-51.c @@ -0,0 +1,54 @@ +/* { dg-do run { target powerpc*-*-* } } */ +/* { dg-do run { target i?86-*-* x86_64-*-* } } */ +/* { dg-options "-O2 -ftree-vectorize -fdump-tree-vect-stats -maltivec" { target powerpc*-*-* } } */ +/* { dg-options "-O2 -ftree-vectorize -fdump-tree-vect-stats -msse" { target i?86-*-* x86_64-*-* } } */ + +#include +#include "tree-vect.h" + +#define N 256 + + +void bar (const float *pa, const float *pb, const float *pc) +{ + int i; + + /* check results: */ + for (i = 0; i < N; i++) + { + if (pa[i] != (pb[i] * pc[i])) + abort (); + } + + return; +} + + +int +main1 (int n, float *pa, float *pb, float *pc) +{ + int i; + + for (i = 0; i < n; i++) + { + pa[i] = pb[i] * pc[i]; + } + + bar (pa,pb,pc); + + return 0; +} + +int main (void) +{ + int i; + float a[N]; + float b[N] = {0,3,6,9,12,15,18,21,24,27,30,33,36,39,42,45,48,51,54,57}; + float c[N] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19}; + + check_vect (); + + main1 (N,a,b,c); +} + +/* { dg-final { scan-tree-dump-times "vectorized 1 loops" 1 "vect" { xfail *-*-* } } } */ diff --git a/gcc/testsuite/gcc.dg/vect/vect-52.c b/gcc/testsuite/gcc.dg/vect/vect-52.c new file mode 100644 index 00000000000..32a584b2a0b --- /dev/null +++ b/gcc/testsuite/gcc.dg/vect/vect-52.c @@ -0,0 +1,56 @@ +/* { dg-do run { target powerpc*-*-* } } */ +/* { dg-do run { target i?86-*-* x86_64-*-* } } */ +/* { dg-options "-O2 -ftree-vectorize -fdump-tree-vect-stats -maltivec" { target powerpc*-*-* } } */ +/* { dg-options "-O2 -ftree-vectorize -fdump-tree-vect-stats -msse" { target i?86-*-* x86_64-*-* } } */ + +#include +#include "tree-vect.h" + +#define N 256 + +typedef float afloat __attribute__ ((__aligned__(16))); + +void bar (float *pa, float *pb, float *pc) +{ + int i; + + /* check results: */ + for (i = 0; i < N; i++) + { + if (pa[i] != (pb[i] * pc[i])) + abort (); + } + + return; +} + + +int +main1 (int n, afloat * __restrict__ pa, float * __restrict__ pb, float * __restrict__ pc) +{ + int i; + + for (i = 0; i < n; i++) + { + pa[i] = pb[i] * pc[i]; + } + + bar (pa,pb,pc); + + return 0; +} + +int main (void) +{ + int i; + afloat a[N]; + afloat b[N] = {0,3,6,9,12,15,18,21,24,27,30,33,36,39,42,45,48,51,54,57,60}; + afloat c[N] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20}; + + check_vect (); + + main1 (N,a,&b[1],c); + main1 (N,a,&b[1],&c[1]); +} + +/* { dg-final { scan-tree-dump-times "vectorized 1 loops" 1 "vect" { xfail *-*-* } } } */ diff --git a/gcc/testsuite/gcc.dg/vect/vect-53.c b/gcc/testsuite/gcc.dg/vect/vect-53.c new file mode 100644 index 00000000000..4b99304caf3 --- /dev/null +++ b/gcc/testsuite/gcc.dg/vect/vect-53.c @@ -0,0 +1,56 @@ +/* { dg-do run { target powerpc*-*-* } } */ +/* { dg-do run { target i?86-*-* x86_64-*-* } } */ +/* { dg-options "-O2 -ftree-vectorize -fdump-tree-vect-stats -maltivec" { target powerpc*-*-* } } */ +/* { dg-options "-O2 -ftree-vectorize -fdump-tree-vect-stats -msse" { target i?86-*-* x86_64-*-* } } */ + +#include +#include "tree-vect.h" + +#define N 256 + +typedef float afloat __attribute__ ((__aligned__(16))); + +void bar (const float *pa, const float *pb, const float *pc) +{ + int i; + + /* check results: */ + for (i = 0; i < N; i++) + { + if (pa[i] != (pb[i] * pc[i])) + abort (); + } + + return; +} + + +int +main1 (int n, afloat *pa, float *pb, float *pc) +{ + int i; + + for (i = 0; i < n; i++) + { + pa[i] = pb[i] * pc[i]; + } + + bar (pa,pb,pc); + + return 0; +} + +int main (void) +{ + int i; + afloat a[N]; + afloat b[N+1] = {0,3,6,9,12,15,18,21,24,27,30,33,36,39,42,45,48,51,54,57,60}; + afloat c[N+1] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20}; + + check_vect (); + + main1 (N,a,&b[1],c); + main1 (N,a,&b[1],&c[1]); +} + +/* { dg-final { scan-tree-dump-times "vectorized 1 loops" 1 "vect" { xfail *-*-* } } } */ diff --git a/gcc/testsuite/gcc.dg/vect/vect-54.c b/gcc/testsuite/gcc.dg/vect/vect-54.c new file mode 100644 index 00000000000..5ab9e026f42 --- /dev/null +++ b/gcc/testsuite/gcc.dg/vect/vect-54.c @@ -0,0 +1,55 @@ +/* { dg-do run { target powerpc*-*-* } } */ +/* { dg-do run { target i?86-*-* x86_64-*-* } } */ +/* { dg-options "-O2 -ftree-vectorize -fdump-tree-vect-stats -maltivec" { target powerpc*-*-* } } */ +/* { dg-options "-O2 -ftree-vectorize -fdump-tree-vect-stats -msse" { target i?86-*-* x86_64-*-* } } */ + +#include +#include "tree-vect.h" + +#define N 256 + +typedef float afloat __attribute__ ((__aligned__(16))); + +void bar (afloat *pa, afloat *pb, afloat *pc) +{ + int i; + + /* check results: */ + for (i = 0; i < N/2; i++) + { + if (pa[i+1] != (pb[i+1] * pc[i+1])) + abort (); + } + + return; +} + + +int +main1 (afloat * __restrict__ pa, afloat * __restrict__ pb, afloat * __restrict__ pc) +{ + int i; + + for (i = 0; i < N/2; i++) + { + pa[i+1] = pb[i+1] * pc[i+1]; + } + + bar (pa,pb,pc); + + return 0; +} + +int main (void) +{ + int i; + afloat a[N]; + afloat b[N] = {0,3,6,9,12,15,18,21,24,27,30,33,36,39,42,45,48,51,54,57}; + afloat c[N] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19}; + + check_vect (); + + main1 (a,b,c); +} + +/* { dg-final { scan-tree-dump-times "vectorized 1 loops" 1 "vect" { xfail *-*-* } } } */ diff --git a/gcc/testsuite/gcc.dg/vect/vect-55.c b/gcc/testsuite/gcc.dg/vect/vect-55.c new file mode 100644 index 00000000000..2257a2312f3 --- /dev/null +++ b/gcc/testsuite/gcc.dg/vect/vect-55.c @@ -0,0 +1,55 @@ +/* { dg-do run { target powerpc*-*-* } } */ +/* { dg-do run { target i?86-*-* x86_64-*-* } } */ +/* { dg-options "-O2 -ftree-vectorize -fdump-tree-vect-stats -maltivec" { target powerpc*-*-* } } */ +/* { dg-options "-O2 -ftree-vectorize -fdump-tree-vect-stats -msse" { target i?86-*-* x86_64-*-* } } */ + +#include +#include "tree-vect.h" + +#define N 256 + +typedef float afloat __attribute__ ((__aligned__(16))); + +void bar (afloat *pa, afloat *pb, afloat *pc) +{ + int i; + + /* check results: */ + for (i = 0; i < N/2; i++) + { + if (pa[i+1] != (pb[i+1] * pc[i+1])) + abort (); + } + + return; +} + + +int +main1 (afloat * pa, afloat * pb, afloat * pc) +{ + int i; + + for (i = 0; i < N/2; i++) + { + pa[i+1] = pb[i+1] * pc[i+1]; + } + + bar (pa,pb,pc); + + return 0; +} + +int main (void) +{ + int i; + afloat a[N]; + afloat b[N] = {0,3,6,9,12,15,18,21,24,27,30,33,36,39,42,45,48,51,54,57}; + afloat c[N] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19}; + + check_vect (); + + main1 (a,b,c); +} + +/* { dg-final { scan-tree-dump-times "vectorized 1 loops" 1 "vect" { xfail *-*-* } } } */ diff --git a/gcc/testsuite/gcc.dg/vect/vect-56.c b/gcc/testsuite/gcc.dg/vect/vect-56.c new file mode 100644 index 00000000000..0e20137bebd --- /dev/null +++ b/gcc/testsuite/gcc.dg/vect/vect-56.c @@ -0,0 +1,55 @@ +/* { dg-do run { target powerpc*-*-* } } */ +/* { dg-do run { target i?86-*-* x86_64-*-* } } */ +/* { dg-options "-O2 -ftree-vectorize -fdump-tree-vect-stats -maltivec" { target powerpc*-*-* } } */ +/* { dg-options "-O2 -ftree-vectorize -fdump-tree-vect-stats -msse" { target i?86-*-* x86_64-*-* } } */ + +#include +#include "tree-vect.h" + +#define N 256 + +typedef float afloat __attribute__ ((__aligned__(16))); + +void bar (afloat *pa, afloat *pb, afloat *pc) +{ + int i; + + /* check results: */ + for (i = 0; i < N/2; i++) + { + if (pa[i] != (pb[i+1] * pc[i+1])) + abort (); + } + + return; +} + + +int +main1 (afloat * __restrict__ pa, afloat * __restrict__ pb, afloat * __restrict__ pc) +{ + int i; + + for (i = 0; i < N/2; i++) + { + pa[i] = pb[i+1] * pc[i+1]; + } + + bar (pa,pb,pc); + + return 0; +} + +int main (void) +{ + int i; + afloat a[N]; + afloat b[N] = {0,3,6,9,12,15,18,21,24,27,30,33,36,39,42,45,48,51,54,57}; + afloat c[N] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19}; + + check_vect (); + + main1 (a,b,c); +} + +/* { dg-final { scan-tree-dump-times "vectorized 1 loops" 1 "vect" { xfail *-*-* } } } */ diff --git a/gcc/testsuite/gcc.dg/vect/vect-57.c b/gcc/testsuite/gcc.dg/vect/vect-57.c new file mode 100644 index 00000000000..0e675d7755c --- /dev/null +++ b/gcc/testsuite/gcc.dg/vect/vect-57.c @@ -0,0 +1,55 @@ +/* { dg-do run { target powerpc*-*-* } } */ +/* { dg-do run { target i?86-*-* x86_64-*-* } } */ +/* { dg-options "-O2 -ftree-vectorize -fdump-tree-vect-stats -maltivec" { target powerpc*-*-* } } */ +/* { dg-options "-O2 -ftree-vectorize -fdump-tree-vect-stats -msse" { target i?86-*-* x86_64-*-* } } */ + +#include +#include "tree-vect.h" + +#define N 256 + +typedef float afloat __attribute__ ((__aligned__(16))); + +void bar (afloat *pa, afloat *pb, afloat *pc) +{ + int i; + + /* check results: */ + for (i = 0; i < N/2; i++) + { + if (pa[i] != (pb[i+1] * pc[i+1])) + abort (); + } + + return; +} + + +int +main1 (afloat * pa, afloat * pb, afloat * pc) +{ + int i; + + for (i = 0; i < N/2; i++) + { + pa[i] = pb[i+1] * pc[i+1]; + } + + bar (pa,pb,pc); + + return 0; +} + +int main (void) +{ + int i; + afloat a[N]; + afloat b[N] = {0,3,6,9,12,15,18,21,24,27,30,33,36,39,42,45,48,51,54,57}; + afloat c[N] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19}; + + check_vect (); + + main1 (a,b,c); +} + +/* { dg-final { scan-tree-dump-times "vectorized 1 loops" 1 "vect" { xfail *-*-* } } } */ diff --git a/gcc/testsuite/gcc.dg/vect/vect-58.c b/gcc/testsuite/gcc.dg/vect/vect-58.c new file mode 100644 index 00000000000..57c27795f1c --- /dev/null +++ b/gcc/testsuite/gcc.dg/vect/vect-58.c @@ -0,0 +1,56 @@ +/* { dg-do run { target powerpc*-*-* } } */ +/* { dg-do run { target i?86-*-* x86_64-*-* } } */ +/* { dg-options "-O2 -ftree-vectorize -fdump-tree-vect-stats -maltivec" { target powerpc*-*-* } } */ +/* { dg-options "-O2 -ftree-vectorize -fdump-tree-vect-stats -msse" { target i?86-*-* x86_64-*-* } } */ + +#include +#include "tree-vect.h" + +#define N 256 + +typedef float afloat __attribute__ ((__aligned__(16))); + +void bar (afloat *pa, afloat *pb, afloat *pc) +{ + int i; + + /* check results: */ + for (i = 0; i < N/2; i++) + { + if (pa[i+1] != (pb[i+1] * pc[i+1])) + abort (); + } + + return; +} + + +int +main1 (int n , afloat * __restrict__ pa, afloat * __restrict__ pb, afloat * __restrict__ pc) +{ + int i; + + for (i = 0; i < n/2; i++) + { + pa[i+1] = pb[i+1] * pc[i+1]; + } + + bar (pa,pb,pc); + + return 0; +} + +int main (void) +{ + int i; + int n=N; + afloat a[N]; + afloat b[N] = {0,3,6,9,12,15,18,21,24,27,30,33,36,39,42,45,48,51,54,57}; + afloat c[N] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19}; + + check_vect (); + + main1 (n,a,b,c); +} + +/* { dg-final { scan-tree-dump-times "vectorized 1 loops" 1 "vect" { xfail *-*-* } } } */ diff --git a/gcc/testsuite/gcc.dg/vect/vect-59.c b/gcc/testsuite/gcc.dg/vect/vect-59.c new file mode 100644 index 00000000000..3dfbe19e988 --- /dev/null +++ b/gcc/testsuite/gcc.dg/vect/vect-59.c @@ -0,0 +1,56 @@ +/* { dg-do run { target powerpc*-*-* } } */ +/* { dg-do run { target i?86-*-* x86_64-*-* } } */ +/* { dg-options "-O2 -ftree-vectorize -fdump-tree-vect-stats -maltivec" { target powerpc*-*-* } } */ +/* { dg-options "-O2 -ftree-vectorize -fdump-tree-vect-stats -msse" { target i?86-*-* x86_64-*-* } } */ + +#include +#include "tree-vect.h" + +#define N 256 + +typedef float afloat __attribute__ ((__aligned__(16))); + +void bar (afloat *pa, afloat *pb, afloat *pc) +{ + int i; + + /* check results: */ + for (i = 0; i < N/2; i++) + { + if (pa[i+1] != (pb[i+1] * pc[i+1])) + abort (); + } + + return; +} + + +int +main1 (int n , afloat * pa, afloat * pb, afloat * pc) +{ + int i; + + for (i = 0; i < n/2; i++) + { + pa[i+1] = pb[i+1] * pc[i+1]; + } + + bar (pa,pb,pc); + + return 0; +} + +int main (void) +{ + int i; + int n=N; + afloat a[N]; + afloat b[N] = {0,3,6,9,12,15,18,21,24,27,30,33,36,39,42,45,48,51,54,57}; + afloat c[N] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19}; + + check_vect (); + + main1 (n,a,b,c); +} + +/* { dg-final { scan-tree-dump-times "vectorized 1 loops" 1 "vect" { xfail *-*-* } } } */ diff --git a/gcc/testsuite/gcc.dg/vect/vect-6.c b/gcc/testsuite/gcc.dg/vect/vect-6.c new file mode 100644 index 00000000000..2671fd7e037 --- /dev/null +++ b/gcc/testsuite/gcc.dg/vect/vect-6.c @@ -0,0 +1,61 @@ +/* { dg-do run { target powerpc*-*-* } } */ +/* { dg-do run { target i?86-*-* x86_64-*-* } } */ +/* { dg-options "-O2 -ftree-vectorize -fdump-tree-vect-stats -maltivec" { target powerpc*-*-* } } */ +/* { dg-options "-O2 -ftree-vectorize -fdump-tree-vect-stats -msse2" { target i?86-*-* x86_64-*-* } } */ + +#include +#include "tree-vect.h" + +#define N 16 + +float results1[N] = {192.00,240.00,288.00,336.00,384.00,432.00,480.00,528.00,0.00}; +float results2[N] = {0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,54.00,120.00,198.00,288.00,390.00,504.00,630.00}; + +int main1 () +{ + int i; + float a[N] = {0}; + float e[N] = {0}; + float b[N] = {0,3,6,9,12,15,18,21,24,27,30,33,36,39,42,45}; + float c[N] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15}; + + for (i = 0; i < N/2; i++) + { + a[i] = b[i+N/2] * c[i+N/2] - b[i] * c[i]; + e[i+N/2] = b[i] * c[i+N/2] + b[i+N/2] * c[i]; + } + + /* check results: */ + for (i=0; i +#include "tree-vect.h" + +#define N 256 + +typedef float afloat __attribute__ ((__aligned__(16))); + +void bar (afloat *pa, afloat *pb, afloat *pc) +{ + int i; + + /* check results: */ + for (i = 0; i < N/2; i++) + { + if (pa[i] != (pb[i+1] * pc[i+1])) + abort (); + } + + return; +} + + +int +main1 (int n , afloat * __restrict__ pa, afloat * __restrict__ pb, afloat * __restrict__ pc) +{ + int i; + + for (i = 0; i < n/2; i++) + { + pa[i] = pb[i+1] * pc[i+1]; + } + + bar (pa,pb,pc); + + return 0; +} + +int main (void) +{ + int i; + int n=N; + afloat a[N]; + afloat b[N] = {0,3,6,9,12,15,18,21,24,27,30,33,36,39,42,45,48,51,54,57}; + afloat c[N] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19}; + + check_vect (); + + main1 (n,a,b,c); +} + +/* { dg-final { scan-tree-dump-times "vectorized 1 loops" 1 "vect" { xfail *-*-* } } } */ diff --git a/gcc/testsuite/gcc.dg/vect/vect-61.c b/gcc/testsuite/gcc.dg/vect/vect-61.c new file mode 100644 index 00000000000..257ef388fc5 --- /dev/null +++ b/gcc/testsuite/gcc.dg/vect/vect-61.c @@ -0,0 +1,56 @@ +/* { dg-do run { target powerpc*-*-* } } */ +/* { dg-do run { target i?86-*-* x86_64-*-* } } */ +/* { dg-options "-O2 -ftree-vectorize -fdump-tree-vect-stats -maltivec" { target powerpc*-*-* } } */ +/* { dg-options "-O2 -ftree-vectorize -fdump-tree-vect-stats -msse" { target i?86-*-* x86_64-*-* } } */ + +#include +#include "tree-vect.h" + +#define N 256 + +typedef float afloat __attribute__ ((__aligned__(16))); + +void bar (afloat *pa, afloat *pb, afloat *pc) +{ + int i; + + /* check results: */ + for (i = 0; i < N/2; i++) + { + if (pa[i] != (pb[i+1] * pc[i+1])) + abort (); + } + + return; +} + + +int +main1 (int n , afloat * pa, afloat * pb, afloat * pc) +{ + int i; + + for (i = 0; i < n/2; i++) + { + pa[i] = pb[i+1] * pc[i+1]; + } + + bar (pa,pb,pc); + + return 0; +} + +int main (void) +{ + int i; + int n=N; + afloat a[N]; + afloat b[N] = {0,3,6,9,12,15,18,21,24,27,30,33,36,39,42,45,48,51,54,57}; + afloat c[N] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19}; + + check_vect (); + + main1 (n,a,b,c); +} + +/* { dg-final { scan-tree-dump-times "vectorized 1 loops" 1 "vect" { xfail *-*-* } } } */ diff --git a/gcc/testsuite/gcc.dg/vect/vect-7.c b/gcc/testsuite/gcc.dg/vect/vect-7.c new file mode 100644 index 00000000000..76e0106d7b4 --- /dev/null +++ b/gcc/testsuite/gcc.dg/vect/vect-7.c @@ -0,0 +1,52 @@ +/* { dg-do run { target powerpc*-*-* } } */ +/* { dg-do run { target i?86-*-* x86_64-*-* } } */ +/* { dg-options "-O2 -ftree-vectorize -fdump-tree-vect-stats -maltivec" { target powerpc*-*-* } } */ +/* { dg-options "-O2 -ftree-vectorize -fdump-tree-vect-stats -msse2" { target i?86-*-* x86_64-*-* } } */ + +#include +#include "tree-vect.h" + +#define N 128 + +int main1 () +{ + int i; + short sa[N]; + short sb[N]; + + for (i = 0; i < N; i++) + { + sb[i] = 5; + } + + /* check results: */ + for (i = 0; i < N; i++) + { + if (sb[i] != 5) + abort (); + } + + for (i = 0; i < N; i++) + { + sa[i] = sb[i] + 100; + } + + /* check results: */ + for (i = 0; i < N; i++) + { + if (sa[i] != 105) + abort (); + } + + return 0; +} + +int main (void) +{ + check_vect (); + + return main1 (); +} + +/* xfail: local arrays can't be aligned on a boundary greater than STACK_BOUNDARY */ +/* { dg-final { scan-tree-dump-times "vectorized 2 loops" 1 "vect" {xfail i?86-*-* x86_64-*-*} } } */ diff --git a/gcc/testsuite/gcc.dg/vect/vect-8.c b/gcc/testsuite/gcc.dg/vect/vect-8.c new file mode 100644 index 00000000000..08c986cb9af --- /dev/null +++ b/gcc/testsuite/gcc.dg/vect/vect-8.c @@ -0,0 +1,40 @@ +/* { dg-do run { target powerpc*-*-* } } */ +/* { dg-do run { target i?86-*-* x86_64-*-* } } */ +/* { dg-options "-O2 -ftree-vectorize -fdump-tree-vect-stats -maltivec" { target powerpc*-*-* } } */ +/* { dg-options "-O2 -ftree-vectorize -fdump-tree-vect-stats -msse2" { target i?86-*-* x86_64-*-* } } */ + +#include +#include "tree-vect.h" + +#define N 16 + +float b[N] = {0,2,4,6,8,10,12,14,16,18,20,22,24,26,28,30}; +float a[N]; + +int main1 (int n) +{ + int i; + + /* Vectorized: unknown loop bound). */ + for (i = 0; i < n; i++){ + a[i] = b[i]; + } + + /* check results: */ + for (i = 0; i < n; i++) + { + if (a[i] != b[i]) + abort (); + } + + return 0; +} + +int main (void) +{ + check_vect (); + + return main1 (N); +} + +/* { dg-final { scan-tree-dump-times "vectorized 1 loops" 1 "vect" { xfail *-*-* } } } */ diff --git a/gcc/testsuite/gcc.dg/vect/vect-9.c b/gcc/testsuite/gcc.dg/vect/vect-9.c new file mode 100644 index 00000000000..0501bb8eadd --- /dev/null +++ b/gcc/testsuite/gcc.dg/vect/vect-9.c @@ -0,0 +1,40 @@ +/* { dg-do run { target powerpc*-*-* } } */ +/* { dg-do run { target i?86-*-* x86_64-*-* } } */ +/* { dg-options "-O2 -ftree-vectorize -fdump-tree-vect-stats -maltivec" { target powerpc*-*-* } } */ +/* { dg-options "-O2 -ftree-vectorize -fdump-tree-vect-stats -msse2" { target i?86-*-* x86_64-*-* } } */ + +#include +#include "tree-vect.h" + +#define N 16 + +int main1 () +{ + int i; + short sb[N] = {0,3,6,9,12,15,18,21,24,27,30,33,36,39,42,45}; + int ia[N]; + + /* Not vetorizable yet (type cast). */ + for (i = 0; i < N; i++) + { + ia[i] = (int) sb[i]; + } + + /* check results: */ + for (i = 0; i < N; i++) + { + if (ia[i] != (int) sb[i]) + abort (); + } + + return 0; +} + +int main (void) +{ + check_vect (); + + return main1 (); +} + +/* { dg-final { scan-tree-dump-times "vectorized 1 loops" 1 "vect" { xfail *-*-* } } } */ diff --git a/gcc/testsuite/gcc.dg/vect/vect-all.c b/gcc/testsuite/gcc.dg/vect/vect-all.c new file mode 100644 index 00000000000..a36d3084baa --- /dev/null +++ b/gcc/testsuite/gcc.dg/vect/vect-all.c @@ -0,0 +1,218 @@ +/* { dg-do run { target powerpc*-*-* } } */ +/* { dg-do run { target i?86-*-* x86_64-*-* } } */ +/* { dg-options "-O2 -ftree-vectorize -fdump-tree-vect-stats -maltivec" { target powerpc*-*-* } } */ +/* { dg-options "-O2 -ftree-vectorize -fdump-tree-vect-stats -msse2" { target i?86-*-* x86_64-*-* } } */ + +#include +#include "tree-vect.h" + +#define N 16 + +int iadd_results[N] = {0,6,12,18,24,30,36,42,48,54,60,66,72,78,84,90}; +float fadd_results[N] = {0.0,6.0,12.0,18.0,24.0,30.0,36.0,42.0,48.0,54.0,60.0,66.0,72.0,78.0,84.0,90.0}; +float fmul_results[N] = {0.0,3.0,12.0,27.0,48.0,75.0,108.0,147.0,192.0,243.0,300.0,363.0,432.0,507.0,588.0,675.0}; +float fresults1[N] = {192.00,240.00,288.00,336.00,384.00,432.00,480.00,528.00,48.00,54.00,60.00,66.00,72.00,78.00,84.00,90.00}; +float fresults2[N] = {0.00,6.00,12.00,18.00,24.00,30.00,36.00,42.00,0.00,54.00,120.00,198.00,288.00,390.00,504.00,630.00}; + +/****************************************************/ +void icheck_results (int *a, int *results) +{ + int i; + for (i = 0; i < N; i++) + { + if (a[i] != results[i]) + abort (); + } +} + +void fcheck_results (float *a, float *results) +{ + int i; + for (i = 0; i < N; i++) + { + if (a[i] != results[i]) + abort (); + } +} + +void +fbar_mul (float *a) +{ + fcheck_results (a, fmul_results); +} + +void +fbar_add (float *a) +{ + fcheck_results (a, fadd_results); +} + +void +ibar_add (int *a) +{ + icheck_results (a, iadd_results); +} + +void +fbar1 (float *a) +{ + fcheck_results (a, fresults1); +} + +void +fbar2 (float *a) +{ + fcheck_results (a, fresults2); +} + + +/* All of the loops below are currently vectorizable. */ + +int +main1 () +{ + int i,j; + float a[N]; + float e[N]; + float b[N] = {0,3,6,9,12,15,18,21,24,27,30,33,36,39,42,45}; + float c[N] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15}; + float d[N] = {0,2,4,6,8,10,12,14,16,18,20,22,24,26,28,30}; + int ic[N] = {0,3,6,9,12,15,18,21,24,27,30,33,36,39,42,45}; + int ib[N] = {0,3,6,9,12,15,18,21,24,27,30,33,36,39,42,45}; + int ia[N]; + char cb[N] = {0,3,6,9,12,15,18,21,24,27,30,33,36,39,42,45}; + char ca[N]; + short sa[N]; + + /* Test 1: copy chars. */ + for (i = 0; i < N; i++) + { + ca[i] = cb[i]; + } + /* check results: */ + for (i = 0; i < N; i++) + { + if (ca[i] != cb[i]) + abort (); + } + + + /* Test 2: fp mult. */ + for (i = 0; i < N; i++) + { + a[i] = b[i] * c[i]; + } + fbar_mul (a); + + + /* Test 3: mixed types (int, fp), same nunits in vector. */ + for (i = 0; i < N; i++) + { + a[i] = b[i] + c[i] + d[i]; + e[i] = b[i] + c[i] + d[i]; + ia[i] = ib[i] + ic[i]; + } + ibar_add (ia); + fbar_add (a); + fbar_add (e); + + + /* Test 4: access with offset. */ + for (i = 0; i < N/2; i++) + { + a[i] = b[i+N/2] * c[i+N/2] - b[i] * c[i]; + e[i+N/2] = b[i] * c[i+N/2] + b[i+N/2] * c[i]; + } + fbar1 (a); + fbar2 (e); + + + /* Test 5: access with offset */ + for (i = 1; i <=N-4; i++) + { + a[i+3] = b[i-1]; + } + /* check results: */ + for (i = 1; i <=N-4; i++) + { + if (a[i+3] != b[i-1]) + abort (); + } + + + /* Test 6 - loop induction with stride != 1. */ + i = 0; + j = 0; + while (i < 5*N) + { + a[j] = c[j]; + i += 5; + j++; + } + /* check results: */ + for (i = 0; i 0; i--) + { + a[N-i] = d[N-i]; + } + /* check results: */ + for (i = 0; i 0 ? b[i] : 0); + } + fbar (a); + + + /* Test 8 - cross-iteration cycle. */ + diff = 0; + for (i = 0; i < N; i++) { + diff += (cb[i] - cc[i]); + } + ibar (&diff); + + + /* Test 9 - outer-loop not attempted; inner-loop has cross + iteration cycle and multi-dimensional arrays. */ + diff = 0; + for (i = 0; i < N; i++) { + for (i = 0; i < N; i++) { + diff += (image[i][j] - block[i][j]); + } + } + ibar (&diff); + + + /* Test 10 - induction. */ + for ( i = 0; i < N; i++) { + a[i] = i; + } + fbar (a); + + + /* Test 11 - reverse access and forward access. */ + for (i = N; i > 0; i--) + { + a[N-i] = b[i-1]; + } + /* check results: */ + for (i = 0; i + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +GCC is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING. If not, write to the Free +Software Foundation, 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ + +/* Loop Vectorization Pass. + + This pass tries to vectorize loops. This first implementation focuses on + simple inner-most loops, with no conditional control flow, and a set of + simple operations which vector form can be expressed using existing + tree codes (PLUS, MULT etc). + + For example, the vectorizer transforms the following simple loop: + + short a[N]; short b[N]; short c[N]; int i; + + for (i=0; ihandlers[(int) V8HImode].insn_code). If + the value found is CODE_FOR_nothing, then there's no target support, and + we can't vectorize the stmt. + + For additional information on this project see: + http://gcc.gnu.org/projects/tree-ssa/vectorization.html +*/ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tm.h" +#include "errors.h" +#include "ggc.h" +#include "tree.h" +#include "target.h" + +#include "rtl.h" +#include "basic-block.h" +#include "diagnostic.h" +#include "tree-flow.h" +#include "tree-dump.h" +#include "timevar.h" +#include "cfgloop.h" +#include "cfglayout.h" +#include "expr.h" +#include "optabs.h" +#include "tree-chrec.h" +#include "tree-data-ref.h" +#include "tree-scalar-evolution.h" +#include "tree-vectorizer.h" +#include "tree-pass.h" + +/* Main analysis functions. */ +static loop_vec_info vect_analyze_loop (struct loop *); +static loop_vec_info vect_analyze_loop_form (struct loop *); +static bool vect_analyze_data_refs (loop_vec_info); +static bool vect_mark_stmts_to_be_vectorized (loop_vec_info); +static bool vect_analyze_scalar_cycles (loop_vec_info); +static bool vect_analyze_data_ref_accesses (loop_vec_info); +static bool vect_analyze_data_refs_alignment (loop_vec_info); +static void vect_compute_data_refs_alignment (loop_vec_info); +static bool vect_analyze_operations (loop_vec_info); + +/* Main code transformation functions. */ +static void vect_transform_loop (loop_vec_info, struct loops *); +static void vect_transform_loop_bound (loop_vec_info); +static bool vect_transform_stmt (tree, block_stmt_iterator *); +static bool vectorizable_load (tree, block_stmt_iterator *, tree *); +static bool vectorizable_store (tree, block_stmt_iterator *, tree *); +static bool vectorizable_operation (tree, block_stmt_iterator *, tree *); +static bool vectorizable_assignment (tree, block_stmt_iterator *, tree *); +static void vect_align_data_ref (tree); +static void vect_enhance_data_refs_alignment (loop_vec_info); + +/* Utility functions for the analyses. */ +static bool vect_is_simple_use (tree , struct loop *, tree *); +static bool exist_non_indexing_operands_for_use_p (tree, tree); +static bool vect_is_simple_iv_evolution (unsigned, tree, tree *, tree *, bool); +static void vect_mark_relevant (varray_type, tree); +static bool vect_stmt_relevant_p (tree, loop_vec_info); +static tree vect_get_loop_niters (struct loop *, HOST_WIDE_INT *); +static void vect_compute_data_ref_alignment + (struct data_reference *, loop_vec_info); +static bool vect_analyze_data_ref_access (struct data_reference *); +static bool vect_get_first_index (tree, tree *); +static bool vect_can_force_dr_alignment_p (tree, unsigned int); +static tree vect_get_base_decl_and_bit_offset (tree, tree *); +static struct data_reference * vect_analyze_pointer_ref_access (tree, tree, bool); + +/* Utility functions for the code transformation. */ +static tree vect_create_destination_var (tree, tree); +static tree vect_create_data_ref (tree, block_stmt_iterator *); +static tree vect_create_index_for_array_ref (tree, block_stmt_iterator *); +static tree get_vectype_for_scalar_type (tree); +static tree vect_get_new_vect_var (tree, enum vect_var_kind, const char *); +static tree vect_get_vec_def_for_operand (tree, tree); +static tree vect_init_vector (tree, tree); +static void vect_finish_stmt_generation + (tree stmt, tree vec_stmt, block_stmt_iterator *bsi); + +/* Utilities for creation and deletion of vec_info structs. */ +loop_vec_info new_loop_vec_info (struct loop *loop); +void destroy_loop_vec_info (loop_vec_info); +stmt_vec_info new_stmt_vec_info (tree stmt, struct loop *loop); + +static bool vect_debug_stats (struct loop *loop); +static bool vect_debug_details (struct loop *loop); + + +/* Function new_stmt_vec_info. + + Create and initialize a new stmt_vec_info struct for STMT. */ + +stmt_vec_info +new_stmt_vec_info (tree stmt, struct loop *loop) +{ + stmt_vec_info res; + res = (stmt_vec_info) xcalloc (1, sizeof (struct _stmt_vec_info)); + + STMT_VINFO_TYPE (res) = undef_vec_info_type; + STMT_VINFO_STMT (res) = stmt; + STMT_VINFO_LOOP (res) = loop; + STMT_VINFO_RELEVANT_P (res) = 0; + STMT_VINFO_VECTYPE (res) = NULL; + STMT_VINFO_VEC_STMT (res) = NULL; + STMT_VINFO_DATA_REF (res) = NULL; + STMT_VINFO_MEMTAG (res) = NULL; + + return res; +} + + +/* Function new_loop_vec_info. + + Create and initialize a new loop_vec_info struct for LOOP, as well as + stmt_vec_info structs for all the stmts in LOOP. */ + +loop_vec_info +new_loop_vec_info (struct loop *loop) +{ + loop_vec_info res; + basic_block *bbs; + block_stmt_iterator si; + unsigned int i; + + res = (loop_vec_info) xcalloc (1, sizeof (struct _loop_vec_info)); + + bbs = get_loop_body (loop); + + /* Create stmt_info for all stmts in the loop. */ + for (i = 0; i < loop->num_nodes; i++) + { + basic_block bb = bbs[i]; + for (si = bsi_start (bb); !bsi_end_p (si); bsi_next (&si)) + { + tree stmt = bsi_stmt (si); + stmt_ann_t ann; + + get_stmt_operands (stmt); + ann = stmt_ann (stmt); + set_stmt_info (ann, new_stmt_vec_info (stmt, loop)); + } + } + + LOOP_VINFO_LOOP (res) = loop; + LOOP_VINFO_BBS (res) = bbs; + LOOP_VINFO_EXIT_COND (res) = NULL; + LOOP_VINFO_NITERS (res) = -1; + LOOP_VINFO_VECTORIZABLE_P (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"); + return res; +} + + +/* Function destroy_loop_vec_info. + + Free LOOP_VINFO struct, as well as all the stmt_vec_info structs of all the + stmts in the loop. */ + +void +destroy_loop_vec_info (loop_vec_info loop_vinfo) +{ + struct loop *loop; + basic_block *bbs; + int nbbs; + block_stmt_iterator si; + int j; + + if (!loop_vinfo) + return; + + loop = LOOP_VINFO_LOOP (loop_vinfo); + + bbs = LOOP_VINFO_BBS (loop_vinfo); + nbbs = loop->num_nodes; + + for (j = 0; j < nbbs; j++) + { + basic_block bb = bbs[j]; + for (si = bsi_start (bb); !bsi_end_p (si); bsi_next (&si)) + { + tree stmt = bsi_stmt (si); + stmt_ann_t ann = stmt_ann (stmt); + stmt_vec_info stmt_info = vinfo_for_stmt (stmt); + free (stmt_info); + set_stmt_info (ann, NULL); + } + } + + free (LOOP_VINFO_BBS (loop_vinfo)); + varray_clear (LOOP_VINFO_DATAREF_WRITES (loop_vinfo)); + varray_clear (LOOP_VINFO_DATAREF_READS (loop_vinfo)); + + free (loop_vinfo); +} + + +/* Function debug_loop_stats. + + For vectorization statistics dumps. */ + +static bool +vect_debug_stats (struct loop *loop) +{ + basic_block bb; + block_stmt_iterator si; + tree node = NULL_TREE; + + if (!dump_file || !(dump_flags & TDF_STATS)) + return false; + + if (!loop) + { + fprintf (dump_file, "\n"); + return true; + } + + if (!loop->header) + return false; + + bb = loop->header; + + for (si = bsi_start (bb); !bsi_end_p (si); bsi_next (&si)) + { + node = bsi_stmt (si); + if (node && EXPR_P (node) && EXPR_LOCUS (node)) + break; + } + + if (node && EXPR_P (node) && EXPR_LOCUS (node) + && EXPR_FILENAME (node) && EXPR_LINENO (node)) + { + fprintf (dump_file, "\nloop at %s:%d: ", + EXPR_FILENAME (node), EXPR_LINENO (node)); + return true; + } + + return false; +} + + +/* Function debug_loop_details. + + For vectorization debug dumps. */ + +static bool +vect_debug_details (struct loop *loop) +{ + basic_block bb; + block_stmt_iterator si; + tree node = NULL_TREE; + + if (!dump_file || !(dump_flags & TDF_DETAILS)) + return false; + + if (!loop) + { + fprintf (dump_file, "\n"); + return true; + } + + if (!loop->header) + return false; + + bb = loop->header; + + for (si = bsi_start (bb); !bsi_end_p (si); bsi_next (&si)) + { + node = bsi_stmt (si); + if (node && EXPR_P (node) && EXPR_LOCUS (node)) + break; + } + + if (node && EXPR_P (node) && EXPR_LOCUS (node) + && EXPR_FILENAME (node) && EXPR_LINENO (node)) + { + fprintf (dump_file, "\nloop at %s:%d: ", + EXPR_FILENAME (node), EXPR_LINENO (node)); + return true; + } + + return false; +} + + +/* THIS IS A COPY OF THE FUNCTION IN TREE-SSA-IVOPTS.C, MODIFIED + TO NOT USE FORCE_GIMPLE_OPERAND. When that function is accepted + into he mainline, This function can go away and be replaced by it. + Creates an induction variable with value BASE + STEP * iteration in + LOOP. It is expected that neither BASE nor STEP are shared with + other expressions (unless the sharing rules allow this). Use VAR + as a base var_decl for it (if NULL, a new temporary will be + created). The increment will occur at INCR_POS (after it if AFTER + is true, before it otherwise). The ssa versions of the variable + before and after increment will be stored in VAR_BEFORE and + VAR_AFTER (unless they are NULL). */ + +static void +vect_create_iv_simple (tree base, tree step, tree var, struct loop *loop, + block_stmt_iterator *incr_pos, bool after, + tree *var_before, tree *var_after) +{ + tree stmt, stmts, initial; + tree vb, va; + stmts = NULL; + + if (!var) + { + var = create_tmp_var (TREE_TYPE (base), "ivtmp"); + add_referenced_tmp_var (var); + } + + vb = make_ssa_name (var, build_empty_stmt ()); + if (var_before) + *var_before = vb; + va = make_ssa_name (var, build_empty_stmt ()); + if (var_after) + *var_after = va; + + stmt = build (MODIFY_EXPR, void_type_node, va, + build (PLUS_EXPR, TREE_TYPE (base), vb, step)); + SSA_NAME_DEF_STMT (va) = stmt; + if (after) + bsi_insert_after (incr_pos, stmt, BSI_NEW_STMT); + else + bsi_insert_before (incr_pos, stmt, BSI_NEW_STMT); + + /* Our base is always a GIMPLE variable, thus, we don't need to + force_gimple_operand it. */ + initial = base; + if (stmts) + { + edge pe = loop_preheader_edge (loop); + bsi_insert_on_edge (pe, stmts); + } + + stmt = create_phi_node (vb, loop->header); + SSA_NAME_DEF_STMT (vb) = stmt; + add_phi_arg (&stmt, initial, loop_preheader_edge (loop)); + add_phi_arg (&stmt, va, loop_latch_edge (loop)); +} + + +/* Function vect_get_base_decl_and_bit_offset + + Get the decl from which the data reference REF is based, + and compute the OFFSET from it in bits on the way. + FORNOW: Handle only component-refs that consist of + VAR_DECLs (no ARRAY_REF or INDIRECT_REF). */ + +static tree +vect_get_base_decl_and_bit_offset (tree ref, tree *offset) +{ + tree decl; + if (TREE_CODE (ref) == VAR_DECL) + return ref; + + if (TREE_CODE (ref) == COMPONENT_REF) + { + tree this_offset; + tree oprnd0 = TREE_OPERAND (ref, 0); + tree oprnd1 = TREE_OPERAND (ref, 1); + + this_offset = bit_position (oprnd1); + if (!host_integerp (this_offset,1)) + return NULL_TREE; + + decl = vect_get_base_decl_and_bit_offset (oprnd0, offset); + + if (decl) + { + *offset = int_const_binop (PLUS_EXPR, *offset, this_offset, 1); + + if (!host_integerp (*offset,1) || TREE_OVERFLOW (*offset)) + return NULL_TREE; + + if (vect_debug_details (NULL)) + { + print_generic_expr (dump_file, ref, TDF_SLIM); + fprintf (dump_file, " --> total offset for ref: "); + print_generic_expr (dump_file, *offset, TDF_SLIM); + } + } + + return decl; + } + + /* TODO: extend to handle more cases. */ + return NULL_TREE; +} + + +/* Function vect_force_dr_alignment_p. + + Returns whether the alignment of a DECL can be forced to be aligned + on ALIGNMENT bit boundary. */ + +static bool +vect_can_force_dr_alignment_p (tree decl, unsigned int alignment) +{ + if (TREE_CODE (decl) != VAR_DECL) + return false; + + if (DECL_EXTERNAL (decl)) + return false; + + if (TREE_STATIC (decl)) + return (alignment <= MAX_OFILE_ALIGNMENT); + else + return (alignment <= STACK_BOUNDARY); +} + + +/* Function vect_get_new_vect_var. + + Returns a name for a new variable. The current naming scheme appends the + prefix "vect_" or "vect_p" (depending on the value of VAR_KIND) to + the name of vectorizer generated variables, and appends that to NAME if + provided. */ + +static tree +vect_get_new_vect_var (tree type, enum vect_var_kind var_kind, const char *name) +{ + const char *prefix; + int prefix_len; + tree new_vect_var; + + if (var_kind == vect_simple_var) + prefix = "vect_"; + else + prefix = "vect_p"; + + prefix_len = strlen (prefix); + + if (name) + new_vect_var = create_tmp_var (type, concat (prefix, name, NULL)); + else + new_vect_var = create_tmp_var (type, prefix); + + return new_vect_var; +} + + +/* Function create_index_for_array_ref. + + Create (and return) an index variable, along with it's update chain in the + loop. This variable will be used to access a memory location in a vector + operation. + + Input: + STMT: The stmt that contains a memory data-ref. + BSI: The block_stmt_iterator where STMT is. Any new stmts created by this + function can be added here, or in the loop pre-header. + + FORNOW: We are only handling array accesses with step 1. */ + +static tree +vect_create_index_for_array_ref (tree stmt, block_stmt_iterator *bsi) +{ + stmt_vec_info stmt_info = vinfo_for_stmt (stmt); + struct loop *loop = STMT_VINFO_LOOP (stmt_info); + struct data_reference *dr = STMT_VINFO_DATA_REF (stmt_info); + tree expr = DR_REF (dr); + tree access_fn; + tree init, step; + loop_vec_info loop_info = loop->aux; + int vectorization_factor = LOOP_VINFO_VECT_FACTOR (loop_info); + tree vf; + tree array_first_index; + tree indx_before_incr, indx_after_incr; + int loopnum = loop->num; + bool ok; +#ifdef ENABLE_CHECKING + varray_type access_fns = DR_ACCESS_FNS (dr); + + /* FORNOW: handling only one dimensional arrays. */ + if (VARRAY_ACTIVE_SIZE (access_fns) != 1) + abort (); + + if (!vectorization_factor) + abort (); +#endif + + access_fn = DR_ACCESS_FN (dr, 0); + ok = vect_is_simple_iv_evolution (loopnum, access_fn, &init, &step, true) + && vect_get_first_index (expr, &array_first_index); + +#ifdef ENABLE_CHECKING + if (!ok) + abort (); + + /* FORNOW: Handling only constant 'init'. */ + if (TREE_CODE (init) != INTEGER_CST) + abort (); +#endif + + vf = build_int_cst (unsigned_type_node, vectorization_factor, 0); + + if (vect_debug_details (NULL)) + { + fprintf (dump_file, "int vf = %d",vectorization_factor); + fprintf (dump_file, ", vf:"); + print_generic_expr (dump_file, vf, TDF_SLIM); + fprintf (dump_file, ", init:"); + print_generic_expr (dump_file, init, TDF_SLIM); + fprintf (dump_file, ", array_first_index:"); + print_generic_expr (dump_file, array_first_index, TDF_SLIM); + } + + /* Calculate the 'init' of the new index. + init = (init - array_first_index) / vectorization_factor */ + init = int_const_binop (TRUNC_DIV_EXPR, + int_const_binop (MINUS_EXPR, init, array_first_index, 1), + vf, 1); + + /* Calculate the 'step' of the new index. FORNOW: always 1. */ + step = size_one_node; + + if (vect_debug_details (NULL)) + { + fprintf (dump_file, "create iv for ("); + print_generic_expr (dump_file, init, TDF_SLIM); + fprintf (dump_file, ", + ,"); + print_generic_expr (dump_file, step, TDF_SLIM); + fprintf (dump_file, ")"); + } + + /* both init and step are guaranted to be gimple expressions, + so we can use vect_create_iv_simple. */ + vect_create_iv_simple (init, step, NULL, loop, bsi, false, + &indx_before_incr, &indx_after_incr); + + return indx_before_incr; +} + + +/* Function get_vectype_for_scalar_type. + + Returns the vector type corresponding to SCALAR_TYPE as supported + by the target. */ + +static tree +get_vectype_for_scalar_type (tree scalar_type) +{ + enum machine_mode inner_mode = TYPE_MODE (scalar_type); + int nbytes = GET_MODE_SIZE (inner_mode); + int nunits; + + if (nbytes == 0) + return NULL_TREE; + + /* FORNOW: Only a single vector size per target (UNITS_PER_SIMD_WORD) + is expected. */ + nunits = UNITS_PER_SIMD_WORD / nbytes; + + return build_vector_type (scalar_type, nunits); +} + + +/* Function vect_align_data_ref. + + Handle mislignment of a memory accesses. + + FORNOW: Can't handle misaligned accesses. + Make sure that the dataref is aligned. */ + +static void +vect_align_data_ref (tree stmt) +{ + stmt_vec_info stmt_info = vinfo_for_stmt (stmt); + struct data_reference *dr = STMT_VINFO_DATA_REF (stmt_info); + + /* FORNOW: can't handle misaligned accesses; + all accesses expected to be aligned. */ + if (!aligned_access_p (dr)) + abort (); +} + + +/* Function vect_create_data_ref. + + Create a memory reference expression for vector access, to be used in a + vector load/store stmt. + + Input: + STMT: a stmt that references memory. expected to be of the form + MODIFY_EXPR or MODIFY_EXPR . + BSI: block_stmt_iterator where new stmts can be added. + + Output: + 1. Declare a new ptr to vector_type, and have it point to the array base. + For example, for vector of type V8HI: + v8hi *p0; + p0 = (v8hi *)&a; + 2. Create a data-reference based on the new vector pointer p0, and using + a new index variable 'idx'. Return the expression '(*p0)[idx]'. + + FORNOW: handle only aligned and consecutive accesses. */ + +static tree +vect_create_data_ref (tree stmt, block_stmt_iterator *bsi) +{ + tree new_base; + tree data_ref; + tree idx; + tree vec_stmt; + tree new_temp; + stmt_vec_info stmt_info = vinfo_for_stmt (stmt); + tree vectype = STMT_VINFO_VECTYPE (stmt_info); + tree vect_ptr_type; + tree vect_ptr; + tree addr_ref; + v_may_def_optype v_may_defs = STMT_V_MAY_DEF_OPS (stmt); + v_must_def_optype v_must_defs = STMT_V_MUST_DEF_OPS (stmt); + vuse_optype vuses = STMT_VUSE_OPS (stmt); + int nvuses, nv_may_defs, nv_must_defs; + int i; + struct data_reference *dr = STMT_VINFO_DATA_REF (stmt_info); + tree array_type; + tree base_addr = NULL_TREE; + struct loop *loop = STMT_VINFO_LOOP (stmt_info); + edge pe; + tree tag; + tree addr_expr; + tree scalar_ptr_type; + + /* FORNOW: make sure the data reference is aligned. */ + vect_align_data_ref (stmt); + + addr_ref = DR_BASE_NAME (dr); + + array_type = build_array_type (vectype, 0); + TYPE_ALIGN (array_type) = TYPE_ALIGN (TREE_TYPE (addr_ref)); + vect_ptr_type = build_pointer_type (array_type); + scalar_ptr_type = build_pointer_type (TREE_TYPE (addr_ref)); + + if (vect_debug_details (NULL)) + { + fprintf (dump_file, "create array_ref of type: "); + print_generic_expr (dump_file, vectype, TDF_SLIM); + } + + /*** create: vectype_array *p; ***/ + vect_ptr = vect_get_new_vect_var (vect_ptr_type, vect_pointer_var, + get_name (addr_ref)); + add_referenced_tmp_var (vect_ptr); + +#ifdef ENABLE_CHECKING + if (TREE_CODE (addr_ref) != VAR_DECL + && TREE_CODE (addr_ref) != COMPONENT_REF + && TREE_CODE (addr_ref) != SSA_NAME) + abort (); +#endif + + if (vect_debug_details (NULL)) + { + if (TREE_CODE (addr_ref) == VAR_DECL) + fprintf (dump_file, "vectorizing an array ref: "); + else if (TREE_CODE (addr_ref) == SSA_NAME) + fprintf (dump_file, "vectorizing a pointer ref: "); + else if (TREE_CODE (addr_ref) == COMPONENT_REF) + fprintf (dump_file, "vectorizing a record ref: "); + print_generic_expr (dump_file, addr_ref, TDF_SLIM); + } + + /* Get base address: */ + if (TREE_CODE (addr_ref) == SSA_NAME) + base_addr = addr_ref; + else + base_addr = build_fold_addr_expr (addr_ref); + + /* Handle aliasing: */ + tag = STMT_VINFO_MEMTAG (stmt_info); +#ifdef ENABLE_CHECKING + if (!tag) + abort (); +#endif + get_var_ann (vect_ptr)->type_mem_tag = tag; + + /* Mark for renaming all aliased variables + (i.e, the may-aliases of the type-mem-tag) */ + nvuses = NUM_VUSES (vuses); + nv_may_defs = NUM_V_MAY_DEFS (v_may_defs); + nv_must_defs = NUM_V_MUST_DEFS (v_must_defs); + for (i = 0; i < nvuses; i++) + { + tree use = VUSE_OP (vuses, i); + if (TREE_CODE (use) == SSA_NAME) + bitmap_set_bit (vars_to_rename, var_ann (SSA_NAME_VAR (use))->uid); + } + for (i = 0; i < nv_may_defs; i++) + { + tree def = V_MAY_DEF_RESULT (v_may_defs, i); + if (TREE_CODE (def) == SSA_NAME) + bitmap_set_bit (vars_to_rename, var_ann (SSA_NAME_VAR (def))->uid); + } + for (i = 0; i < nv_must_defs; i++) + { + tree def = V_MUST_DEF_OP (v_must_defs, i); + if (TREE_CODE (def) == SSA_NAME) + bitmap_set_bit (vars_to_rename, var_ann (SSA_NAME_VAR (def))->uid); + } + + pe = loop_preheader_edge (loop); + + /*** create: p = (vectype *)&a; ***/ + + /* addr_expr = &a */ + addr_expr = vect_get_new_vect_var (scalar_ptr_type, vect_pointer_var, + get_name (addr_ref)); + add_referenced_tmp_var (addr_expr); + vec_stmt = build2 (MODIFY_EXPR, void_type_node, addr_expr, base_addr); + new_temp = make_ssa_name (addr_expr, vec_stmt); + TREE_OPERAND (vec_stmt, 0) = new_temp; + bsi_insert_on_edge (pe, vec_stmt); + + /* vect_ptr = (vectype_array *)&a; */ + vec_stmt = fold_convert (vect_ptr_type, new_temp); + vec_stmt = build2 (MODIFY_EXPR, void_type_node, vect_ptr, vec_stmt); + new_temp = make_ssa_name (vect_ptr, vec_stmt); + TREE_OPERAND (vec_stmt, 0) = new_temp; + bsi_insert_on_edge (pe, vec_stmt); + + /*** create data ref: '(*p)[idx]' ***/ + + idx = vect_create_index_for_array_ref (stmt, bsi); + + new_base = build_fold_indirect_ref (new_temp); + data_ref = build4 (ARRAY_REF, vectype, new_base, idx, NULL_TREE, NULL_TREE); + + if (vect_debug_details (NULL)) + { + fprintf (dump_file, "created new data-ref: "); + print_generic_expr (dump_file, data_ref, TDF_SLIM); + } + + return data_ref; +} + + +/* Function vect_create_destination_var. + + Create a new temporary of type VECTYPE. */ + +static tree +vect_create_destination_var (tree scalar_dest, tree vectype) +{ + tree vec_dest; + const char *new_name; + +#ifdef ENABLE_CHECKING + if (TREE_CODE (scalar_dest) != SSA_NAME) + abort (); +#endif + + new_name = get_name (scalar_dest); + if (!new_name) + new_name = "var_"; + vec_dest = vect_get_new_vect_var (vectype, vect_simple_var, new_name); + add_referenced_tmp_var (vec_dest); + + return vec_dest; +} + + +/* Function vect_init_vector. + + Insert a new stmt (INIT_STMT) that initializes a new vector variable with + the vector elements of VECTOR_VAR. Return the DEF of INIT_STMT. It will be + used in the vectorization of STMT. */ + +static tree +vect_init_vector (tree stmt, tree vector_var) +{ + stmt_vec_info stmt_vinfo = vinfo_for_stmt (stmt); + struct loop *loop = STMT_VINFO_LOOP (stmt_vinfo); + tree new_var; + tree init_stmt; + tree vectype = STMT_VINFO_VECTYPE (stmt_vinfo); + tree vec_oprnd; + edge pe; + tree new_temp; + + new_var = vect_get_new_vect_var (vectype, vect_simple_var, "cst_"); + add_referenced_tmp_var (new_var); + + init_stmt = build2 (MODIFY_EXPR, vectype, new_var, vector_var); + new_temp = make_ssa_name (new_var, init_stmt); + TREE_OPERAND (init_stmt, 0) = new_temp; + + pe = loop_preheader_edge (loop); + bsi_insert_on_edge (pe, init_stmt); + + if (vect_debug_details (NULL)) + { + fprintf (dump_file, "created new init_stmt: "); + print_generic_expr (dump_file, init_stmt, TDF_SLIM); + } + + vec_oprnd = TREE_OPERAND (init_stmt, 0); + return vec_oprnd; +} + + +/* Function vect_get_vec_def_for_operand. + + OP is an operand in STMT. This function returns a (vector) def that will be + used in the vectorized stmt for STMT. + + In the case that OP is an SSA_NAME which is defined in the loop, then + STMT_VINFO_VEC_STMT of the defining stmt holds the relevant def. + + In case OP is an invariant or constant, a new stmt that creates a vector def + needs to be introduced. */ + +static tree +vect_get_vec_def_for_operand (tree op, tree stmt) +{ + tree vec_oprnd; + tree vec_stmt; + tree def_stmt; + stmt_vec_info def_stmt_info = NULL; + stmt_vec_info stmt_vinfo = vinfo_for_stmt (stmt); + tree vectype = STMT_VINFO_VECTYPE (stmt_vinfo); + int nunits = GET_MODE_NUNITS (TYPE_MODE (vectype)); + struct loop *loop = STMT_VINFO_LOOP (stmt_vinfo); + basic_block bb; + tree vec_inv; + tree t = NULL_TREE; + tree def; + int i; + + if (vect_debug_details (NULL)) + { + fprintf (dump_file, "vect_get_vec_def_for_operand: "); + print_generic_expr (dump_file, op, TDF_SLIM); + } + + /** ===> Case 1: operand is a constant. **/ + + if (TREE_CODE (op) == INTEGER_CST || TREE_CODE (op) == REAL_CST) + { + /* Create 'vect_cst_ = {cst,cst,...,cst}' */ + + tree vec_cst; + stmt_vec_info stmt_vinfo = vinfo_for_stmt (stmt); + tree vectype = STMT_VINFO_VECTYPE (stmt_vinfo); + int nunits = GET_MODE_NUNITS (TYPE_MODE (vectype)); + tree t = NULL_TREE; + int i; + + /* Build a tree with vector elements. */ + if (vect_debug_details (NULL)) + fprintf (dump_file, "Create vector_cst. nunits = %d", nunits); + + for (i = nunits - 1; i >= 0; --i) + { + t = tree_cons (NULL_TREE, op, t); + } + vec_cst = build_vector (vectype, t); + return vect_init_vector (stmt, vec_cst); + } + +#ifdef ENABLE_CHECKING + if (TREE_CODE (op) != SSA_NAME) + abort (); +#endif + + /** ===> Case 2: operand is an SSA_NAME - find the stmt that defines it. **/ + + def_stmt = SSA_NAME_DEF_STMT (op); + def_stmt_info = vinfo_for_stmt (def_stmt); + + if (vect_debug_details (NULL)) + { + fprintf (dump_file, "vect_get_vec_def_for_operand: def_stmt: "); + print_generic_expr (dump_file, def_stmt, TDF_SLIM); + } + + + /** ==> Case 2.1: operand is defined inside the loop. **/ + + if (def_stmt_info) + { + /* Get the def from the vectorized stmt. */ + + vec_stmt = STMT_VINFO_VEC_STMT (def_stmt_info); +#ifdef ENABLE_CHECKING + if (!vec_stmt) + abort (); +#endif + vec_oprnd = TREE_OPERAND (vec_stmt, 0); + return vec_oprnd; + } + + + /** ==> Case 2.2: operand is defined by the loop-header phi-node - + it is a reduction/induction. **/ + + bb = bb_for_stmt (def_stmt); + if (TREE_CODE (def_stmt) == PHI_NODE && flow_bb_inside_loop_p (loop, bb)) + { + if (vect_debug_details (NULL)) + fprintf (dump_file, "reduction/induction - unsupported."); + abort (); /* FORNOW no support for reduction/induction. */ + } + + + /** ==> Case 2.3: operand is defined outside the loop - + it is a loop invariant. */ + + switch (TREE_CODE (def_stmt)) + { + case PHI_NODE: + def = PHI_RESULT (def_stmt); + break; + case MODIFY_EXPR: + def = TREE_OPERAND (def_stmt, 0); + break; + case NOP_EXPR: + def = TREE_OPERAND (def_stmt, 0); +#ifdef ENABLE_CHECKING + if (!IS_EMPTY_STMT (def_stmt)) + abort (); +#endif + def = op; + break; + default: + if (vect_debug_details (NULL)) + { + fprintf (dump_file, "unsupported defining stmt: "); + print_generic_expr (dump_file, def_stmt, TDF_SLIM); + } + abort (); + } + + /* Build a tree with vector elements. Create 'vec_inv = {inv,inv,..,inv}' */ + + if (vect_debug_details (NULL)) + fprintf (dump_file, "Create vector_inv."); + + for (i = nunits - 1; i >= 0; --i) + { + t = tree_cons (NULL_TREE, def, t); + } + + vec_inv = build_constructor (vectype, t); + return vect_init_vector (stmt, vec_inv); +} + + +/* Function vect_finish_stmt_generation. + + Insert a new stmt. */ + +static void +vect_finish_stmt_generation (tree stmt, tree vec_stmt, block_stmt_iterator *bsi) +{ + bsi_insert_before (bsi, vec_stmt, BSI_SAME_STMT); + + if (vect_debug_details (NULL)) + { + fprintf (dump_file, "add new stmt: "); + print_generic_expr (dump_file, vec_stmt, TDF_SLIM); + } + + /* Make sure bsi points to the stmt that is being vectorized. */ + + /* Assumption: any stmts created for the vectorization of smtmt S are + inserted before S. BSI may point to S or some new stmt before it. */ + + while (stmt != bsi_stmt (*bsi) && !bsi_end_p (*bsi)) + bsi_next (bsi); +#ifdef ENABLE_CHECKING + if (stmt != bsi_stmt (*bsi)) + abort (); +#endif +} + + +/* Function vectorizable_assignment. + + Check if STMT performs an assignment (copy) that can be vectorized. + If VEC_STMT is also passed, vectorize the STMT: create a vectorized + stmt to replace it, put it in VEC_STMT, and insert it at BSI. + Return FALSE if not a vectorizable STMT, TRUE otherwise. */ + +static bool +vectorizable_assignment (tree stmt, block_stmt_iterator *bsi, tree *vec_stmt) +{ + tree vec_dest; + tree scalar_dest; + tree op; + tree vec_oprnd; + stmt_vec_info stmt_info = vinfo_for_stmt (stmt); + tree vectype = STMT_VINFO_VECTYPE (stmt_info); + struct loop *loop = STMT_VINFO_LOOP (stmt_info); + tree new_temp; + + /* Is vectorizable assignment? */ + + if (TREE_CODE (stmt) != MODIFY_EXPR) + return false; + + scalar_dest = TREE_OPERAND (stmt, 0); + if (TREE_CODE (scalar_dest) != SSA_NAME) + return false; + + op = TREE_OPERAND (stmt, 1); + if (!vect_is_simple_use (op, loop, NULL)) + { + if (vect_debug_details (NULL)) + fprintf (dump_file, "use not simple."); + return false; + } + + if (!vec_stmt) /* transformation not required. */ + { + STMT_VINFO_TYPE (stmt_info) = assignment_vec_info_type; + return true; + } + + /** Trasform. **/ + if (vect_debug_details (NULL)) + fprintf (dump_file, "transform assignment."); + + /* Handle def. */ + vec_dest = vect_create_destination_var (scalar_dest, vectype); + + /* Handle use. */ + op = TREE_OPERAND (stmt, 1); + vec_oprnd = vect_get_vec_def_for_operand (op, stmt); + + /* Arguments are ready. create the new vector stmt. */ + *vec_stmt = build2 (MODIFY_EXPR, vectype, vec_dest, vec_oprnd); + new_temp = make_ssa_name (vec_dest, *vec_stmt); + TREE_OPERAND (*vec_stmt, 0) = new_temp; + vect_finish_stmt_generation (stmt, *vec_stmt, bsi); + + return true; +} + + +/* Function vectorizable_operation. + + Check if STMT performs a binary or unary operation that can be vectorized. + If VEC_STMT is also passed, vectorize the STMT: create a vectorized + stmt to replace it, put it in VEC_STMT, and insert it at BSI. + Return FALSE if not a vectorizable STMT, TRUE otherwise. */ + +static bool +vectorizable_operation (tree stmt, block_stmt_iterator *bsi, tree *vec_stmt) +{ + tree vec_dest; + tree scalar_dest; + tree operation; + tree op0, op1 = NULL; + tree vec_oprnd0, vec_oprnd1=NULL; + stmt_vec_info stmt_info = vinfo_for_stmt (stmt); + tree vectype = STMT_VINFO_VECTYPE (stmt_info); + struct loop *loop = STMT_VINFO_LOOP (stmt_info); + int i; + enum tree_code code; + enum machine_mode vec_mode; + tree new_temp; + int op_type; + tree op; + optab optab; + + /* Is STMT a vectorizable binary/unary operation? */ + if (TREE_CODE (stmt) != MODIFY_EXPR) + return false; + + if (TREE_CODE (TREE_OPERAND (stmt, 0)) != SSA_NAME) + return false; + + operation = TREE_OPERAND (stmt, 1); + code = TREE_CODE (operation); + optab = optab_for_tree_code (code, vectype); + + /* Support only unary or binary operations. */ + op_type = TREE_CODE_LENGTH (code); + if (op_type != unary_op && op_type != binary_op) + { + if (vect_debug_details (NULL)) + fprintf (dump_file, "num. args = %d (not unary/binary op).", op_type); + return false; + } + + for (i = 0; i < op_type; i++) + { + op = TREE_OPERAND (operation, i); + if (!vect_is_simple_use (op, loop, NULL)) + { + if (vect_debug_details (NULL)) + fprintf (dump_file, "use not simple."); + return false; + } + } + + /* Supportable by target? */ + if (!optab) + { + if (vect_debug_details (NULL)) + fprintf (dump_file, "no optab."); + return false; + } + vec_mode = TYPE_MODE (vectype); + if (optab->handlers[(int) vec_mode].insn_code == CODE_FOR_nothing) + { + if (vect_debug_details (NULL)) + fprintf (dump_file, "op not supported by target."); + return false; + } + + if (!vec_stmt) /* transformation not required. */ + { + STMT_VINFO_TYPE (stmt_info) = op_vec_info_type; + return true; + } + + /** Trasform. **/ + + if (vect_debug_details (NULL)) + fprintf (dump_file, "transform binary/unary operation."); + + /* Handle def. */ + scalar_dest = TREE_OPERAND (stmt, 0); + vec_dest = vect_create_destination_var (scalar_dest, vectype); + + /* Handle uses. */ + op0 = TREE_OPERAND (operation, 0); + vec_oprnd0 = vect_get_vec_def_for_operand (op0, stmt); + + if (op_type == binary_op) + { + op1 = TREE_OPERAND (operation, 1); + vec_oprnd1 = vect_get_vec_def_for_operand (op1, stmt); + } + + /* Arguments are ready. create the new vector stmt. */ + + if (op_type == binary_op) + *vec_stmt = build2 (MODIFY_EXPR, vectype, vec_dest, + build2 (code, vectype, vec_oprnd0, vec_oprnd1)); + else + *vec_stmt = build2 (MODIFY_EXPR, vectype, vec_dest, + build1 (code, vectype, vec_oprnd0)); + new_temp = make_ssa_name (vec_dest, *vec_stmt); + TREE_OPERAND (*vec_stmt, 0) = new_temp; + vect_finish_stmt_generation (stmt, *vec_stmt, bsi); + + return true; +} + + +/* Function vectorizable_store. + + Check if STMT defines a non scalar data-ref (array/pointer/structure) that + can be vectorized. + If VEC_STMT is also passed, vectorize the STMT: create a vectorized + stmt to replace it, put it in VEC_STMT, and insert it at BSI. + Return FALSE if not a vectorizable STMT, TRUE otherwise. */ + +static bool +vectorizable_store (tree stmt, block_stmt_iterator *bsi, tree *vec_stmt) +{ + tree scalar_dest; + tree data_ref; + tree op; + tree vec_oprnd1; + stmt_vec_info stmt_info = vinfo_for_stmt (stmt); + tree vectype = STMT_VINFO_VECTYPE (stmt_info); + struct loop *loop = STMT_VINFO_LOOP (stmt_info); + enum machine_mode vec_mode; + + /* Is vectorizable store? */ + + if (TREE_CODE (stmt) != MODIFY_EXPR) + return false; + + scalar_dest = TREE_OPERAND (stmt, 0); + if (TREE_CODE (scalar_dest) != ARRAY_REF + && TREE_CODE (scalar_dest) != INDIRECT_REF) + return false; + + op = TREE_OPERAND (stmt, 1); + if (!vect_is_simple_use (op, loop, NULL)) + { + if (vect_debug_details (NULL)) + fprintf (dump_file, "use not simple."); + return false; + } + + vec_mode = TYPE_MODE (vectype); + /* FORNOW. In some cases can vectorize even if data-type not supported + (e.g. - array initialization with 0). */ + if (mov_optab->handlers[(int)vec_mode].insn_code == CODE_FOR_nothing) + return false; + + if (!STMT_VINFO_DATA_REF (stmt_info)) + return false; + + if (!vec_stmt) /* transformation not required. */ + { + STMT_VINFO_TYPE (stmt_info) = store_vec_info_type; + return true; + } + + /** Trasform. **/ + + if (vect_debug_details (NULL)) + fprintf (dump_file, "transform store"); + + /* Handle use - get the vectorized def from the defining stmt. */ + vec_oprnd1 = vect_get_vec_def_for_operand (op, stmt); + + /* Handle def. */ + data_ref = vect_create_data_ref (stmt, bsi); + + /* Arguments are ready. create the new vector stmt. */ + *vec_stmt = build2 (MODIFY_EXPR, vectype, data_ref, vec_oprnd1); + vect_finish_stmt_generation (stmt, *vec_stmt, bsi); + + return true; +} + + +/* vectorizable_load. + + Check if STMT reads a non scalar data-ref (array/pointer/structure) that + can be vectorized. + If VEC_STMT is also passed, vectorize the STMT: create a vectorized + stmt to replace it, put it in VEC_STMT, and insert it at BSI. + Return FALSE if not a vectorizable STMT, TRUE otherwise. */ + +static bool +vectorizable_load (tree stmt, block_stmt_iterator *bsi, tree *vec_stmt) +{ + tree scalar_dest; + tree vec_dest = NULL; + tree data_ref = NULL; + tree op; + stmt_vec_info stmt_info = vinfo_for_stmt (stmt); + tree vectype = STMT_VINFO_VECTYPE (stmt_info); + tree new_temp; + enum machine_mode vec_mode; + + /* Is vectorizable load? */ + + if (TREE_CODE (stmt) != MODIFY_EXPR) + return false; + + scalar_dest = TREE_OPERAND (stmt, 0); + if (TREE_CODE (scalar_dest) != SSA_NAME) + return false; + + op = TREE_OPERAND (stmt, 1); + if (TREE_CODE (op) != ARRAY_REF && TREE_CODE (op) != INDIRECT_REF) + return false; + + if (!STMT_VINFO_DATA_REF (stmt_info)) + return false; + + vec_mode = TYPE_MODE (vectype); + /* FORNOW. In some cases can vectorize even if data-type not supported + (e.g. - data copies). */ + if (mov_optab->handlers[(int)vec_mode].insn_code == CODE_FOR_nothing) + return false; + + if (!vec_stmt) /* transformation not required. */ + { + STMT_VINFO_TYPE (stmt_info) = load_vec_info_type; + return true; + } + + /** Trasform. **/ + + if (vect_debug_details (NULL)) + fprintf (dump_file, "transform load."); + + /* Handle def. */ + vec_dest = vect_create_destination_var (scalar_dest, vectype); + + /* Handle use. */ + op = TREE_OPERAND (stmt, 1); + data_ref = vect_create_data_ref (stmt, bsi); + + /* Arguments are ready. create the new vector stmt. */ + *vec_stmt = build2 (MODIFY_EXPR, vectype, vec_dest, data_ref); + new_temp = make_ssa_name (vec_dest, *vec_stmt); + TREE_OPERAND (*vec_stmt, 0) = new_temp; + vect_finish_stmt_generation (stmt, *vec_stmt, bsi); + + return true; +} + + +/* Function vect_transform_stmt. + + Create a vectorized stmt to replace STMT, and insert it at BSI. */ + +static bool +vect_transform_stmt (tree stmt, block_stmt_iterator *bsi) +{ + bool is_store = false; + tree vec_stmt = NULL_TREE; + stmt_vec_info stmt_info = vinfo_for_stmt (stmt); + + switch (STMT_VINFO_TYPE (stmt_info)) + { + case op_vec_info_type: + if (!vectorizable_operation (stmt, bsi, &vec_stmt)) + abort (); + break; + + case assignment_vec_info_type: + if (!vectorizable_assignment (stmt, bsi, &vec_stmt)) + abort (); + break; + + case load_vec_info_type: + if (!vectorizable_load (stmt, bsi, &vec_stmt)) + abort (); + break; + + case store_vec_info_type: + if (!vectorizable_store (stmt, bsi, &vec_stmt)) + abort (); + is_store = true; + break; + default: + if (vect_debug_details (NULL)) + fprintf (dump_file, "stmt not supported."); + abort (); + } + + STMT_VINFO_VEC_STMT (stmt_info) = vec_stmt; + + return is_store; +} + + +/* Function vect_transform_loop_bound. + + Create a new exit condition for the loop. */ + +static void +vect_transform_loop_bound (loop_vec_info loop_vinfo) +{ + struct loop *loop = LOOP_VINFO_LOOP (loop_vinfo); + edge exit_edge = loop->exit_edges[0]; + block_stmt_iterator loop_exit_bsi = bsi_last (exit_edge->src); + tree indx_before_incr, indx_after_incr; + tree orig_cond_expr; + HOST_WIDE_INT old_N = 0; + int vf; + tree cond_stmt; + tree new_loop_bound; + tree cond; + tree lb_type; + +#ifdef ENABLE_CHECKING + if (!LOOP_VINFO_NITERS_KNOWN_P (loop_vinfo)) + abort (); +#endif + old_N = LOOP_VINFO_NITERS (loop_vinfo); + vf = LOOP_VINFO_VECT_FACTOR (loop_vinfo); + +#ifdef ENABLE_CHECKING + /* FORNOW: + assuming number-of-iterations divides by the vectorization factor. */ + if (old_N % vf) + abort (); +#endif + + orig_cond_expr = LOOP_VINFO_EXIT_COND (loop_vinfo); +#ifdef ENABLE_CHECKING + if (!orig_cond_expr) + abort (); +#endif + if (orig_cond_expr != bsi_stmt (loop_exit_bsi)) + abort (); + + /* both init and step are guaranted to be gimple expressions, + so we can use vect_create_iv_simple. */ + vect_create_iv_simple (integer_zero_node, integer_one_node, NULL_TREE, loop, + &loop_exit_bsi, false, &indx_before_incr, &indx_after_incr); + + /* bsi_insert is using BSI_NEW_STMT. We need to bump it back + to point to the exit condition. */ + bsi_next (&loop_exit_bsi); + if (bsi_stmt (loop_exit_bsi) != orig_cond_expr) + abort (); + + /* new loop exit test: */ + lb_type = TREE_TYPE (TREE_OPERAND (TREE_OPERAND (orig_cond_expr, 0), 1)); + new_loop_bound = build_int_cst (lb_type, old_N/vf, 0); + + if (exit_edge->flags & EDGE_TRUE_VALUE) /* 'then' edge exits the loop. */ + cond = build2 (GE_EXPR, boolean_type_node, indx_after_incr, new_loop_bound); + else /* 'then' edge loops back. */ + cond = build2 (LT_EXPR, boolean_type_node, indx_after_incr, new_loop_bound); + + cond_stmt = build3 (COND_EXPR, TREE_TYPE (orig_cond_expr), cond, + TREE_OPERAND (orig_cond_expr, 1), TREE_OPERAND (orig_cond_expr, 2)); + + bsi_insert_before (&loop_exit_bsi, cond_stmt, BSI_SAME_STMT); + + /* remove old loop exit test: */ + bsi_remove (&loop_exit_bsi); + + if (vect_debug_details (NULL)) + print_generic_expr (dump_file, cond_stmt, TDF_SLIM); +} + + +/* Function vect_transform_loop. + + The analysis phase has determined that the loop is vectorizable. + Vectorize the loop - created vectorized stmts to replace the scalar + stmts in the loop, and update the loop exit condition. */ + +static void +vect_transform_loop (loop_vec_info loop_vinfo, + struct loops *loops ATTRIBUTE_UNUSED) +{ + 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 i; +#ifdef ENABLE_CHECKING + int vectorization_factor = LOOP_VINFO_VECT_FACTOR (loop_vinfo); +#endif + + if (vect_debug_details (NULL)) + fprintf (dump_file, "\n<>\n"); + + /* 1) Make sure the loop header has exactly two entries + 2) Make sure we have a preheader basic block. */ + + if (!loop->header->pred->pred_next + || loop->header->pred->pred_next->pred_next) + abort (); + + loop_split_edge_with (loop_preheader_edge (loop), NULL); + + + /* FORNOW: the vectorizer supports only loops which body consist + of one basic block (header + empty latch). When the vectorizer will + support more involved loop forms, the order by which the BBs are + traversed need to be reconsidered. */ + + for (i = 0; i < nbbs; i++) + { + basic_block bb = bbs[i]; + + for (si = bsi_start (bb); !bsi_end_p (si);) + { + tree stmt = bsi_stmt (si); + stmt_vec_info stmt_info; + bool is_store; +#ifdef ENABLE_CHECKING + tree vectype; +#endif + + if (vect_debug_details (NULL)) + { + fprintf (dump_file, "------>vectorizing statement: "); + print_generic_expr (dump_file, stmt, TDF_SLIM); + } + stmt_info = vinfo_for_stmt (stmt); +#ifdef ENABLE_CHECKING + if (!stmt_info) + abort (); +#endif + if (!STMT_VINFO_RELEVANT_P (stmt_info)) + { + bsi_next (&si); + continue; + } +#ifdef ENABLE_CHECKING + /* FORNOW: Verify that all stmts operate on the same number of + units and no inner unrolling is necessary. */ + vectype = STMT_VINFO_VECTYPE (stmt_info); + if (GET_MODE_NUNITS (TYPE_MODE (vectype)) != vectorization_factor) + abort (); +#endif + /* -------- vectorize statement ------------ */ + if (vect_debug_details (NULL)) + fprintf (dump_file, "transform statement."); + + is_store = vect_transform_stmt (stmt, &si); + if (is_store) + { + /* free the attached stmt_vec_info and remove the stmt. */ + stmt_ann_t ann = stmt_ann (stmt); + free (stmt_info); + set_stmt_info (ann, NULL); + bsi_remove (&si); + continue; + } + + bsi_next (&si); + } /* stmts in BB */ + } /* BBs in loop */ + + vect_transform_loop_bound (loop_vinfo); + + if (vect_debug_details (loop)) + fprintf (dump_file,"Success! loop vectorized."); + if (vect_debug_stats (loop)) + fprintf (dump_file, "LOOP VECTORIZED."); +} + + +/* Function vect_is_simple_use. + + Input: + LOOP - the loop that is being vectorized. + OPERAND - operand of a stmt in LOOP. + DEF - the defining stmt in case OPERAND is an SSA_NAME. + + Returns whether a stmt with OPERAND can be vectorized. + Supportable operands are constants, loop invariants, and operands that are + defined by the current iteration of the loop. Unsupportable opernads are + those that are defined by a previous iteration of the loop (as is the case + in reduction/induction computations). */ + +static bool +vect_is_simple_use (tree operand, struct loop *loop, tree *def) +{ + tree def_stmt; + basic_block bb; + + if (def) + *def = NULL_TREE; + + if (TREE_CODE (operand) == INTEGER_CST || TREE_CODE (operand) == REAL_CST) + return true; + + if (TREE_CODE (operand) != SSA_NAME) + return false; + + def_stmt = SSA_NAME_DEF_STMT (operand); + if (def_stmt == NULL_TREE ) + { + if (vect_debug_details (NULL)) + fprintf (dump_file, "no def_stmt."); + return false; + } + + /* empty stmt is expected only in case of a function argument. + (Otherwise - we expect a phi_node or a modify_expr). */ + if (IS_EMPTY_STMT (def_stmt)) + { + tree arg = TREE_OPERAND (def_stmt, 0); + if (TREE_CODE (arg) == INTEGER_CST || TREE_CODE (arg) == REAL_CST) + return true; + if (vect_debug_details (NULL)) + { + fprintf (dump_file, "Unexpected empty stmt: "); + print_generic_expr (dump_file, def_stmt, TDF_SLIM); + } + return false; + } + + /* phi_node inside the loop indicates an induction/reduction pattern. + This is not supported yet. */ + bb = bb_for_stmt (def_stmt); + if (TREE_CODE (def_stmt) == PHI_NODE && flow_bb_inside_loop_p (loop, bb)) + { + if (vect_debug_details (NULL)) + fprintf (dump_file, "reduction/induction - unsupported."); + return false; /* FORNOW: not supported yet. */ + } + + /* Expecting a modify_expr or a phi_node. */ + if (TREE_CODE (def_stmt) == MODIFY_EXPR + || TREE_CODE (def_stmt) == PHI_NODE) + { + if (def) + *def = def_stmt; + return true; + } + + return false; +} + + +/* Function vect_analyze_operations. + + Scan the loop stmts and make sure they are all vectorizable. */ + +static bool +vect_analyze_operations (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 vectorization_factor = 0; + int i; + bool ok; + tree scalar_type; + + if (vect_debug_details (NULL)) + fprintf (dump_file, "\n<>\n"); + + for (i = 0; i < nbbs; i++) + { + basic_block bb = bbs[i]; + + for (si = bsi_start (bb); !bsi_end_p (si); bsi_next (&si)) + { + tree stmt = bsi_stmt (si); + int nunits; + stmt_vec_info stmt_info = vinfo_for_stmt (stmt); + tree vectype; + + if (vect_debug_details (NULL)) + { + fprintf (dump_file, "==> examining statement: "); + print_generic_expr (dump_file, stmt, TDF_SLIM); + } +#ifdef ENABLE_CHECKING + if (!stmt_info) + abort (); +#endif + /* skip stmts which do not need to be vectorized. + this is expected to include: + - the COND_EXPR which is the loop exit condition + - any LABEL_EXPRs in the loop + - computations that are used only for array indexing or loop + control */ + + if (!STMT_VINFO_RELEVANT_P (stmt_info)) + { + if (vect_debug_details (NULL)) + fprintf (dump_file, "irrelevant."); + continue; + } + + if (VECTOR_MODE_P (TYPE_MODE (TREE_TYPE (stmt)))) + { + if (vect_debug_stats (loop) || vect_debug_details (loop)) + { + fprintf (dump_file, "not vectorized: vector stmt in loop:"); + print_generic_expr (dump_file, stmt, TDF_SLIM); + } + return false; + } + + if (STMT_VINFO_DATA_REF (stmt_info)) + scalar_type = TREE_TYPE (DR_REF (STMT_VINFO_DATA_REF (stmt_info))); + else if (TREE_CODE (stmt) == MODIFY_EXPR) + scalar_type = TREE_TYPE (TREE_OPERAND (stmt, 0)); + else + scalar_type = TREE_TYPE (stmt); + + if (vect_debug_details (NULL)) + { + fprintf (dump_file, "get vectype for scalar type: "); + print_generic_expr (dump_file, scalar_type, TDF_SLIM); + } + + vectype = get_vectype_for_scalar_type (scalar_type); + if (!vectype) + { + if (vect_debug_stats (loop) || vect_debug_details (loop)) + { + fprintf (dump_file, "not vectorized: unsupported data-type "); + print_generic_expr (dump_file, scalar_type, TDF_SLIM); + } + return false; + } + + if (vect_debug_details (NULL)) + { + fprintf (dump_file, "vectype: "); + print_generic_expr (dump_file, vectype, TDF_SLIM); + } + STMT_VINFO_VECTYPE (stmt_info) = vectype; + + ok = (vectorizable_operation (stmt, NULL, NULL) + || vectorizable_assignment (stmt, NULL, NULL) + || vectorizable_load (stmt, NULL, NULL) + || vectorizable_store (stmt, NULL, NULL)); + + if (!ok) + { + if (vect_debug_stats (loop) || vect_debug_details (loop)) + { + fprintf (dump_file, "not vectorized: stmt not supported: "); + print_generic_expr (dump_file, stmt, TDF_SLIM); + } + return false; + } + + nunits = GET_MODE_NUNITS (TYPE_MODE (vectype)); + if (vect_debug_details (NULL)) + fprintf (dump_file, "nunits = %d", nunits); + + if (vectorization_factor) + { + /* FORNOW: don't allow mixed units. + This restriction will be relaxed in the future. */ + if (nunits != vectorization_factor) + { + if (vect_debug_stats (loop) || vect_debug_details (loop)) + fprintf (dump_file, "not vectorized: mixed data-types"); + return false; + } + } + else + vectorization_factor = nunits; + } + } + + /* TODO: Analyze cost. Decide if worth while to vectorize. */ + if (!vectorization_factor) + { + if (vect_debug_stats (loop) || vect_debug_details (loop)) + fprintf (dump_file, "not vectorized: unsupported data-type"); + return false; + } + LOOP_VINFO_VECT_FACTOR (loop_vinfo) = vectorization_factor; + + /* FORNOW: handle only cases where the loop bound divides by the + vectorization factor. */ + + if (vect_debug_details (NULL)) + fprintf (dump_file, + "vectorization_factor = %d, niters = " HOST_WIDE_INT_PRINT_DEC, + vectorization_factor, LOOP_VINFO_NITERS (loop_vinfo)); + + if (!LOOP_VINFO_NITERS_KNOWN_P (loop_vinfo)) + { + if (vect_debug_stats (loop) || vect_debug_details (loop)) + fprintf (dump_file, "not vectorized: Unknown loop bound."); + return false; + } + + if (LOOP_VINFO_NITERS_KNOWN_P (loop_vinfo) + && LOOP_VINFO_NITERS (loop_vinfo) % vectorization_factor != 0) + { + if (vect_debug_stats (loop) || vect_debug_details (loop)) + fprintf (dump_file, "not vectorized: loop bound doesn't divided by %d.", + vectorization_factor); + return false; + } + + return true; +} + + +/* Function exist_non_indexing_operands_for_use_p + + USE is one of the uses attached to STMT. Check if USE is + used in STMT for anything other than indexing an array. */ + +static bool +exist_non_indexing_operands_for_use_p (tree use, tree stmt) +{ + tree operand; + stmt_vec_info stmt_info = vinfo_for_stmt (stmt); + + /* USE corresponds to some operand in STMT. If there is no data + reference in STMT, then any operand that corresponds to USE + is not indexing an array. */ + if (!STMT_VINFO_DATA_REF (stmt_info)) + return true; + + /* STMT has a data_ref. FORNOW this means that its of one of + the following forms: + -1- ARRAY_REF = var + -2- var = ARRAY_REF + (This should have been verified in analyze_data_refs). + + 'var' in the second case corresponds to a def, not a use, + so USE cannot correspond to any operands that are not used + for array indexing. + + Therefore, all we need to check is if STMT falls into the + first case, and whether var corresponds to USE. */ + + if (TREE_CODE (TREE_OPERAND (stmt, 0)) == SSA_NAME) + return false; + + operand = TREE_OPERAND (stmt, 1); + + if (TREE_CODE (operand) != SSA_NAME) + return false; + + if (operand == use) + return true; + + return false; +} + + +/* Function vect_is_simple_iv_evolution. + + FORNOW: A simple evolution of an induction variables in the loop is + considered a polynomial evolution with constant step. */ + +static bool +vect_is_simple_iv_evolution (unsigned loop_nb, tree access_fn, tree * init, + tree * step, bool strict) +{ + tree init_expr; + tree step_expr; + + tree evolution_part = evolution_part_in_loop_num (access_fn, loop_nb); + + /* When there is no evolution in this loop, the evolution function + is not "simple". */ + if (evolution_part == NULL_TREE) + return false; + + /* When the evolution is a polynomial of degree >= 2 + the evolution function is not "simple". */ + if (tree_is_chrec (evolution_part)) + return false; + + step_expr = evolution_part; + init_expr = initial_condition (access_fn); + + if (vect_debug_details (NULL)) + { + fprintf (dump_file, "step: "); + print_generic_expr (dump_file, step_expr, TDF_SLIM); + fprintf (dump_file, ", init: "); + print_generic_expr (dump_file, init_expr, TDF_SLIM); + } + + *init = init_expr; + *step = step_expr; + + if (TREE_CODE (step_expr) != INTEGER_CST) + { + if (vect_debug_details (NULL)) + fprintf (dump_file, "step unknown."); + return false; + } + + if (strict) + if (!integer_onep (step_expr)) + { + if (vect_debug_details (NULL)) + print_generic_expr (dump_file, step_expr, TDF_SLIM); + return false; + } + + return true; +} + + +/* Function vect_analyze_scalar_cycles. + + Examine the cross iteration def-use cycles of scalar variables, by + analyzing the loop (scalar) PHIs; verify that the cross iteration def-use + cycles that they represent do not impede vectorization. + + FORNOW: Reduction as in the following loop, is not supported yet: + loop1: + for (i=0; iheader; + tree dummy; + + if (vect_debug_details (NULL)) + fprintf (dump_file, "\n<>\n"); + + for (phi = phi_nodes (bb); phi; phi = TREE_CHAIN (phi)) + { + tree access_fn = NULL; + + if (vect_debug_details (NULL)) + { + fprintf (dump_file, "Analyze phi: "); + print_generic_expr (dump_file, phi, TDF_SLIM); + } + + /* Skip virtual phi's. The data dependences that are associated with + virtual defs/uses (i.e., memory accesses) are analyzed elsewhere. */ + + if (!is_gimple_reg (SSA_NAME_VAR (PHI_RESULT (phi)))) + { + if (vect_debug_details (NULL)) + fprintf (dump_file, "virtual phi. skip."); + continue; + } + + /* Analyze the evolution function. */ + + /* FORNOW: The only scalar cross-iteration cycles that we allow are + those of loop induction variables; This property is verified here. + + Furthermore, if that induction variable is used in an operation + that needs to be vectorized (i.e, is not solely used to index + arrays and check the exit condition) - we do not support its + vectorization yet. This property is verified in vect_is_simple_use, + during vect_analyze_operations. */ + + access_fn = instantiate_parameters + (loop, + analyze_scalar_evolution (loop, PHI_RESULT (phi))); + + if (!access_fn) + { + if (vect_debug_stats (loop) || vect_debug_details (loop)) + fprintf (dump_file, "not vectorized: unsupported scalar cycle."); + return false; + } + + if (vect_debug_details (NULL)) + { + fprintf (dump_file, "Access function of PHI: "); + print_generic_expr (dump_file, access_fn, TDF_SLIM); + } + + if (!vect_is_simple_iv_evolution (loop->num, access_fn, &dummy, + &dummy, false)) + { + if (vect_debug_stats (loop) || vect_debug_details (loop)) + fprintf (dump_file, "not vectorized: unsupported scalar cycle."); + return false; + } + } + + return true; +} + + +/* 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, + struct loop *loop) +{ + bool differ_p; + struct data_dependence_relation *ddr; + + if (!array_base_name_differ_p (dra, drb, &differ_p)) + { + if (vect_debug_stats (loop) || vect_debug_details (loop)) + { + fprintf (dump_file, + "not vectorized: can't determine dependence between: "); + print_generic_expr (dump_file, DR_REF (dra), TDF_SLIM); + fprintf (dump_file, " and "); + print_generic_expr (dump_file, DR_REF (drb), TDF_SLIM); + } + 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 (vect_debug_stats (loop) || vect_debug_details (loop)) + { + fprintf (dump_file, + "not vectorized: possible dependence between data-refs "); + print_generic_expr (dump_file, DR_REF (dra), TDF_SLIM); + fprintf (dump_file, " and "); + print_generic_expr (dump_file, 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. + + TODO: dependences which distance is greater than the vectorization factor + can be ignored. */ + +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); + struct loop *loop = LOOP_VINFO_LOOP (loop_vinfo); + + /* Examine store-store (output) dependences. */ + + if (vect_debug_details (NULL)) + fprintf (dump_file, "\n<>\n"); + + if (vect_debug_details (NULL)) + fprintf (dump_file, "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)) + return false; + } + } + + /* Examine load-store (true/anti) dependences. */ + + if (vect_debug_details (NULL)) + fprintf (dump_file, "compare all load-store pairs."); + + for (i = 0; i < VARRAY_ACTIVE_SIZE (loop_read_refs); 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)) + return false; + } + } + + return true; +} + + +/* Function vect_get_first_index. + + REF is a data reference. + If it is an ARRAY_REF: if its lower bound is simple enough, + put it in ARRAY_FIRST_INDEX and return TRUE; otherwise - return FALSE. + If it is not an ARRAY_REF: REF has no "first index"; + ARRAY_FIRST_INDEX in zero, and the function returns TRUE. */ + +static bool +vect_get_first_index (tree ref, tree *array_first_index) +{ + tree array_start; + + if (TREE_CODE (ref) != ARRAY_REF) + *array_first_index = size_zero_node; + else + { + array_start = array_ref_low_bound (ref); + if (!host_integerp (array_start,0)) + { + if (vect_debug_details (NULL)) + { + fprintf (dump_file, "array min val not simple integer cst."); + print_generic_expr (dump_file, array_start, TDF_DETAILS); + } + return false; + } + *array_first_index = array_start; + } + + return true; +} + + +/* Function vect_compute_data_ref_alignment + + Compute the misalignment of the data reference DR. + + FOR NOW: No analysis is actually performed. Misalignment is calculated + only for trivial cases. TODO. */ + +static void +vect_compute_data_ref_alignment (struct data_reference *dr, + loop_vec_info loop_vinfo ATTRIBUTE_UNUSED) +{ + tree stmt = DR_STMT (dr); + tree ref = DR_REF (dr); + tree vectype; + tree access_fn = DR_ACCESS_FN (dr, 0); /* FORNOW: single access_fn. */ + tree init; + tree scalar_type; + tree misalign; + tree array_first_index; + tree array_base = DR_BASE_NAME (dr); + tree base_decl = NULL_TREE; + tree bit_offset = size_zero_node; + tree offset = size_zero_node; + tree unit_bits = build_int_cst (unsigned_type_node, BITS_PER_UNIT, 0); + tree nunits; + tree alignment; + + if (vect_debug_details (NULL)) + fprintf (dump_file, "vect_compute_data_ref_alignment:"); + + /* Initialize misalignment to unknown. */ + DR_MISALIGNMENT (dr) = -1; + + scalar_type = TREE_TYPE (ref); + vectype = get_vectype_for_scalar_type (scalar_type); + if (!vectype) + { + if (vect_debug_details (NULL)) + { + fprintf (dump_file, "no vectype for stmt: "); + print_generic_expr (dump_file, stmt, TDF_SLIM); + fprintf (dump_file, "scalar_type: "); + print_generic_expr (dump_file, scalar_type, TDF_DETAILS); + } + return; + } + + if (TYPE_ALIGN (TREE_TYPE (TREE_TYPE (array_base))) < TYPE_ALIGN (vectype)) + { + base_decl = vect_get_base_decl_and_bit_offset (array_base, &bit_offset); + if (!base_decl) + { + if (vect_debug_details (NULL)) + fprintf (dump_file, "Unknown alignment for access"); + return; + } + + offset = int_const_binop (TRUNC_DIV_EXPR, bit_offset, unit_bits, 1); + bit_offset = int_const_binop (TRUNC_MOD_EXPR, bit_offset, unit_bits, 1); + if (!integer_zerop (bit_offset)) + { + if (vect_debug_details (NULL)) + { + fprintf (dump_file, "bit offset alignment: "); + print_generic_expr (dump_file, bit_offset, TDF_SLIM); + } + return; + } + + if (!base_decl || + (DECL_ALIGN (base_decl) < TYPE_ALIGN (vectype) + && !vect_can_force_dr_alignment_p (base_decl, TYPE_ALIGN (vectype)))) + { + if (vect_debug_details (NULL)) + { + fprintf (dump_file, "can't force alignment of ref: "); + print_generic_expr (dump_file, array_base, TDF_SLIM); + } + return; + } + + if (DECL_ALIGN (base_decl) < TYPE_ALIGN (vectype)) + { + /* Force the alignment of the decl. + NOTE: This is the only change to the code we make during + the analysis phase, before deciding to vectorize the loop. */ + if (vect_debug_details (NULL)) + fprintf (dump_file, "force alignment"); + DECL_ALIGN (base_decl) = TYPE_ALIGN (vectype); + DECL_USER_ALIGN (base_decl) = TYPE_ALIGN (vectype); + } + } + + /* The misalignement is: + (base_alignment + offset + index_access_fn_init) % alignment. + At this point we already guaranteed that base_alignment == 0, + and computed the offset. + It remains to check the first index accessed. */ + + if (!vect_get_first_index (ref, &array_first_index)) + { + if (vect_debug_details (NULL)) + fprintf (dump_file, "no first_index for array."); + return; + } + + /* Check the index of the array_ref. */ + + init = initial_condition (access_fn); + + /* FORNOW: In order to simplify the handling of alignment, we make sure + that the first location at which the array is accessed ('init') is on an + 'NUNITS' boundary, since we are assuming here that 'array base' is aligned. + This is too conservative, since we require that + both {'array_base' is a multiple of NUNITS} && {'init' is a multiple of + NUNITS}, instead of just {('array_base' + 'init') is a multiple of NUNITS}. + This should be relaxed in the future. */ + + if (!init || !host_integerp (init,0)) + { + if (vect_debug_details (NULL)) + fprintf (dump_file, "init not simple INTEGER_CST."); + return; + } + + /* alignment required, in bytes: */ + alignment = build_int_cst (unsigned_type_node, + TYPE_ALIGN (vectype)/BITS_PER_UNIT, 0); + /* bytes per scalar element: */ + nunits = build_int_cst (unsigned_type_node, + GET_MODE_SIZE (TYPE_MODE (scalar_type)), 0); + + /* misalign = (offset + (init-array_first_index)*nunits) % alignment */ + if (vect_debug_details (NULL)) + { + fprintf (dump_file, "misalign = ( offset <"); + print_generic_expr (dump_file, offset, TDF_SLIM); + fprintf (dump_file, "> + (init <"); + print_generic_expr (dump_file, init, TDF_SLIM); + fprintf (dump_file, "> - first_indx <"); + print_generic_expr (dump_file, array_first_index, TDF_SLIM); + fprintf (dump_file, ">) * nunits <"); + print_generic_expr (dump_file, nunits, TDF_SLIM); + fprintf (dump_file, ">) mod alignment <"); + print_generic_expr (dump_file, alignment, TDF_SLIM); + fprintf (dump_file, ">"); + } + + misalign = int_const_binop (MINUS_EXPR, init, array_first_index, 0); + misalign = int_const_binop (MULT_EXPR, misalign, nunits, 0); + misalign = int_const_binop (PLUS_EXPR, misalign, offset, 0); + misalign = int_const_binop (TRUNC_MOD_EXPR, misalign, alignment, 0); + + if (vect_debug_details (NULL)) + { + fprintf (dump_file, "misalign = "); + print_generic_expr (dump_file, misalign, TDF_SLIM); + } + + if (!host_integerp (misalign,1) || TREE_OVERFLOW (misalign)) + { + if (vect_debug_details (NULL)) + fprintf (dump_file, "unexpected misalign value"); + return; + } + + DR_MISALIGNMENT (dr) = tree_low_cst (misalign,1); + + if (vect_debug_details (NULL)) + fprintf (dump_file, "misalign = %d",DR_MISALIGNMENT (dr)); +} + + +/* Function vect_compute_data_refs_alignment + + Compute the misalignment of data references in the loop. + This pass may take place at function granularity instead of at loop + granularity. + + FOR NOW: No analysis is actually performed. Misalignment is calculated + only for trivial cases. TODO. */ + +static void +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); + 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); + vect_compute_data_ref_alignment (dr, loop_vinfo); + } + + for (i = 0; i < VARRAY_ACTIVE_SIZE (loop_read_datarefs); i++) + { + struct data_reference *dr = VARRAY_GENERIC_PTR (loop_read_datarefs, i); + vect_compute_data_ref_alignment (dr, loop_vinfo); + } +} + + +/* Function vect_enhance_data_refs_alignment + + This pass will use loop versioning and loop peeling in order to enhance + the alignment of data references in the loop. + + FOR NOW: we assume that whatever versioning/peeling takes place, only the + original loop is to be vectorized; Any other loops that are created by + the transformations performed in this pass - are not supposed to be + vectorized. This restriction will be relaxed. + + FOR NOW: No transformation is actually performed. TODO. */ + +static void +vect_enhance_data_refs_alignment (loop_vec_info loop_vinfo ATTRIBUTE_UNUSED) +{ + /* + This pass will require a cost model to guide it whether to apply peeling + or versioning or a combination of the two. For example, the scheme that + intel uses when given a loop with several memory accesses, is as follows: + choose one memory access ('p') which alignment you want to force by doing + peeling. Then, either (1) generate a loop in which 'p' is aligned and all + other accesses are not necessarily aligned, or (2) use loop versioning to + generate one loop in which all accesses are aligned, and another loop in + which only 'p' is necessarily aligned. + + ("Automatic Intra-Register Vectorization for the Intel Architecture", + Aart J.C. Bik, Milind Girkar, Paul M. Grey and Ximmin Tian, International + Journal of Parallel Programming, Vol. 30, No. 2, April 2002.) + + Devising a cost model is the most critical aspect of this work. It will + guide us on which access to peel for, whether to use loop versioning, how + many versions to create, etc. The cost model will probably consist of + generic considerations as well as target specific considerations (on + powerpc for example, misaligned stores are more painful than misaligned + loads). + + Here is the general steps involved in alignment enhancements: + + -- original loop, before alignment analysis: + for (i=0; i>\n"); + + + /* This pass may take place at function granularity instead of at loop + granularity. */ + + vect_compute_data_refs_alignment (loop_vinfo); + + + /* This pass will use loop versioning and loop peeling in order to enhance + the alignment of data references in the loop. + FOR NOW: we assume that whatever versioning/peeling took place, the + original loop is to be vectorized. Any other loops that were created by + the transformations performed in this pass - are not supposed to be + vectorized. This restriction will be relaxed. */ + + vect_enhance_data_refs_alignment (loop_vinfo); + + + /* Finally, check that loop can be vectorized. + FOR NOW: Until support for misaligned accesses is in place, only if all + accesses are aligned can the loop be vectorized. This restriction will be + relaxed. */ + + for (i = 0; i < VARRAY_ACTIVE_SIZE (loop_write_datarefs); i++) + { + struct data_reference *dr = VARRAY_GENERIC_PTR (loop_write_datarefs, i); + if (!aligned_access_p (dr)) + { + if (vect_debug_stats (LOOP_VINFO_LOOP (loop_vinfo)) + || vect_debug_details (LOOP_VINFO_LOOP (loop_vinfo))) + fprintf (dump_file, "not vectorized: unaligned store."); + return false; + } + } + + for (i = 0; i < VARRAY_ACTIVE_SIZE (loop_read_datarefs); i++) + { + struct data_reference *dr = VARRAY_GENERIC_PTR (loop_read_datarefs, i); + if (!aligned_access_p (dr)) + { + if (vect_debug_stats (LOOP_VINFO_LOOP (loop_vinfo)) + || vect_debug_details (LOOP_VINFO_LOOP (loop_vinfo))) + fprintf (dump_file, "not vectorized: unaligned load."); + return false; + } + } + + return true; +} + + +/* Function vect_analyze_data_ref_access. + + Analyze the access pattern of the data-reference DR. For now, a data access + has to consecutive and aligned to be considered vectorizable. */ + +static bool +vect_analyze_data_ref_access (struct data_reference *dr) +{ + varray_type access_fns = DR_ACCESS_FNS (dr); + tree access_fn; + tree init, step; + + /* FORNOW: handle only one dimensional arrays. + This restriction will be relaxed in the future. */ + if (VARRAY_ACTIVE_SIZE (access_fns) != 1) + { + if (vect_debug_details (NULL)) + fprintf (dump_file, "multi dimensional array reference."); + return false; + } + access_fn = DR_ACCESS_FN (dr, 0); + + if (!vect_is_simple_iv_evolution (loop_containing_stmt (DR_STMT (dr))->num, + access_fn, &init, &step, true)) + { + if (vect_debug_details (NULL)) + { + fprintf (dump_file, "too complicated access function."); + print_generic_expr (dump_file, access_fn, TDF_SLIM); + } + return false; + } + + return true; +} + + +/* Function vect_analyze_data_ref_accesses. + + Analyze the access pattern of all the data references in the loop. + + FORNOW: the only access pattern that is considered vectorizable is a + simple step 1 (consecutive) access. + + FORNOW: handle only one dimensional arrays, and pointer accesses. */ + +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); + + if (vect_debug_details (NULL)) + fprintf (dump_file, "\n<>\n"); + + for (i = 0; i < VARRAY_ACTIVE_SIZE (loop_write_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_debug_stats (LOOP_VINFO_LOOP (loop_vinfo)) + || vect_debug_details (LOOP_VINFO_LOOP (loop_vinfo))) + fprintf (dump_file, "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) + { + if (vect_debug_stats (LOOP_VINFO_LOOP (loop_vinfo)) + || vect_debug_details (LOOP_VINFO_LOOP (loop_vinfo))) + fprintf (dump_file, "not vectorized: complicated access pattern."); + return false; + } + } + + return true; +} + + +/* 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. + + If the data-ref access is vectorizable, return a data_reference structure + that represents it (DR). Otherwise - return NULL. */ + +static struct data_reference * +vect_analyze_pointer_ref_access (tree memref, tree stmt, bool is_read) +{ + stmt_vec_info stmt_info = vinfo_for_stmt (stmt); + struct loop *loop = STMT_VINFO_LOOP (stmt_info); + tree access_fn = analyze_scalar_evolution (loop, TREE_OPERAND (memref, 0)); + tree init, step; + int step_val; + tree reftype, innertype; + enum machine_mode innermode; + tree indx_access_fn; + int loopnum = loop->num; + struct data_reference *dr; + + if (!access_fn) + { + if (vect_debug_stats (loop) || vect_debug_details (loop)) + fprintf (dump_file, "not vectorized: complicated pointer access."); + return NULL; + } + + if (vect_debug_details (NULL)) + { + fprintf (dump_file, "Access function of ptr: "); + print_generic_expr (dump_file, access_fn, TDF_SLIM); + } + + if (!vect_is_simple_iv_evolution (loopnum, access_fn, &init, &step, false)) + { + if (vect_debug_stats (loop) || vect_debug_details (loop)) + fprintf (dump_file, "not vectorized: pointer access is not simple."); + return NULL; + } + + if (TREE_CODE (init) != SSA_NAME /* FORNOW */ + || !host_integerp (step,0)) + { + if (vect_debug_stats (loop) || vect_debug_details (loop)) + fprintf (dump_file, + "not vectorized: non constant init/step for pointer access."); + return NULL; + } + + step_val = TREE_INT_CST_LOW (step); + + reftype = TREE_TYPE (TREE_OPERAND (memref, 0)); + if (TREE_CODE (reftype) != POINTER_TYPE) + { + if (vect_debug_stats (loop) || vect_debug_details (loop)) + fprintf (dump_file, "not vectorized: unexpected pointer access form."); + return NULL; + } + + reftype = TREE_TYPE (init); + if (TREE_CODE (reftype) != POINTER_TYPE) + { + if (vect_debug_stats (loop) || vect_debug_details (loop)) + fprintf (dump_file, "not vectorized: unexpected pointer access form."); + return NULL; + } + + innertype = TREE_TYPE (reftype); + innermode = TYPE_MODE (innertype); + if (GET_MODE_SIZE (innermode) != step_val) + { + /* FORNOW: support only consecutive access */ + if (vect_debug_stats (loop) || vect_debug_details (loop)) + fprintf (dump_file, "not vectorized: non consecutive access."); + return NULL; + } + + indx_access_fn = + build_polynomial_chrec (loopnum, integer_zero_node, integer_one_node); + if (vect_debug_details (NULL)) + { + fprintf (dump_file, "Access function of ptr indx: "); + print_generic_expr (dump_file, indx_access_fn, TDF_SLIM); + } + dr = init_data_ref (stmt, memref, init, indx_access_fn, is_read); + return dr; +} + + +/* Function vect_analyze_data_refs. + + Find all the data references in the loop. + + FORNOW: Handle aligned INDIRECT_REFs and one dimensional 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) +{ + 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; + + if (vect_debug_details (NULL)) + fprintf (dump_file, "\n<>\n"); + + 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); + v_may_def_optype v_may_defs = STMT_V_MAY_DEF_OPS (stmt); + v_must_def_optype v_must_defs = STMT_V_MUST_DEF_OPS (stmt); + vuse_optype vuses = STMT_VUSE_OPS (stmt); + varray_type *datarefs = NULL; + int nvuses, nv_may_defs, nv_must_defs; + tree memref = NULL; + tree array_base; + tree symbl; + + /* Assumption: there exists a data-ref in stmt, if and only if + it has vuses/vdefs. */ + + if (!vuses && !v_may_defs && !v_must_defs) + continue; + + nvuses = NUM_VUSES (vuses); + nv_may_defs = NUM_V_MAY_DEFS (v_may_defs); + nv_must_defs = NUM_V_MUST_DEFS (v_must_defs); + + if (nvuses && (nv_may_defs || nv_must_defs)) + { + if (vect_debug_details (NULL)) + { + fprintf (dump_file, "unexpected vdefs and vuses in stmt: "); + print_generic_expr (dump_file, stmt, TDF_SLIM); + } + return false; + } + + if (TREE_CODE (stmt) != MODIFY_EXPR) + { + if (vect_debug_details (NULL)) + { + fprintf (dump_file, "unexpected vops in stmt: "); + print_generic_expr (dump_file, stmt, TDF_SLIM); + } + return false; + } + + if (vuses) + { + 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; + } + + if (TREE_CODE (memref) == INDIRECT_REF) + { + dr = vect_analyze_pointer_ref_access (memref, stmt, is_read); + if (! dr) + return false; + symbl = DR_BASE_NAME (dr); + } + else if (TREE_CODE (memref) == ARRAY_REF) + { + tree base; + tree offset = size_zero_node; + array_base = TREE_OPERAND (memref, 0); + + /* FORNOW: make sure that the array is one dimensional. + This restriction will be relaxed in the future. */ + if (TREE_CODE (array_base) == ARRAY_REF) + { + if (vect_debug_stats (loop) || vect_debug_details (loop)) + { + fprintf (dump_file, + "not vectorized: multi-dimensional array."); + print_generic_expr (dump_file, stmt, TDF_SLIM); + } + return false; + } + + dr = analyze_array (stmt, memref, is_read); + + /* Find the relevant symbol for aliasing purposes. */ + base = DR_BASE_NAME (dr); + switch (TREE_CODE (base)) + { + case VAR_DECL: + symbl = base; + break; + /* FORNOW: Disabled. + case INDIRECT_REF: + symbl = TREE_OPERAND (base, 0); + break; + */ + case COMPONENT_REF: + /* CHECKME: could have recorded more accurate information - + i.e, the actual FIELD_DECL that is being referenced - + but later passes expect VAR_DECL as the nmt. */ + symbl = vect_get_base_decl_and_bit_offset (base, &offset); + if (symbl) + break; + /* fall through */ + default: + if (vect_debug_stats (loop) || vect_debug_details (loop)) + { + fprintf (dump_file, + "not vectorized: unhandled struct/class field access "); + print_generic_expr (dump_file, stmt, TDF_SLIM); + } + return false; + } /* switch */ + } + else + { + if (vect_debug_stats (loop) || vect_debug_details (loop)) + { + fprintf (dump_file, "not vectorized: unhandled data ref: "); + print_generic_expr (dump_file, stmt, TDF_SLIM); + } + return false; + } + + /* Find and record the memtag assigned to this data-ref. */ + if (TREE_CODE (symbl) == VAR_DECL) + STMT_VINFO_MEMTAG (stmt_info) = symbl; + else if (TREE_CODE (symbl) == SSA_NAME) + { + tree tag; + symbl = SSA_NAME_VAR (symbl); + tag = get_var_ann (symbl)->type_mem_tag; + if (!tag) + { + tree ptr = TREE_OPERAND (memref, 0); + if (TREE_CODE (ptr) == SSA_NAME) + tag = get_var_ann (SSA_NAME_VAR (ptr))->type_mem_tag; + } + if (!tag) + { + if (vect_debug_stats (loop) || vect_debug_details (loop)) + fprintf (dump_file, "not vectorized: no memtag for ref."); + return false; + } + STMT_VINFO_MEMTAG (stmt_info) = tag; + } + else + { + if (vect_debug_stats (loop) || vect_debug_details (loop)) + { + fprintf (dump_file, "not vectorized: unsupported data-ref: "); + print_generic_expr (dump_file, memref, TDF_SLIM); + } + return false; + } + + VARRAY_PUSH_GENERIC_PTR (*datarefs, dr); + STMT_VINFO_DATA_REF (stmt_info) = dr; + } + } + + return true; +} + + +/* Utility functions used by vect_mark_stmts_to_be_vectorized. */ + +/* Function vect_mark_relevant. + + Mark STMT as "relevant for vectorization" and add it to WORKLIST. */ + +static void +vect_mark_relevant (varray_type worklist, tree stmt) +{ + stmt_vec_info stmt_info; + + if (vect_debug_details (NULL)) + fprintf (dump_file, "mark relevant."); + + if (TREE_CODE (stmt) == PHI_NODE) + { + VARRAY_PUSH_TREE (worklist, stmt); + return; + } + + stmt_info = vinfo_for_stmt (stmt); + + if (!stmt_info) + { + if (vect_debug_details (NULL)) + { + fprintf (dump_file, "mark relevant: no stmt info!!."); + print_generic_expr (dump_file, stmt, TDF_SLIM); + } + return; + } + + if (STMT_VINFO_RELEVANT_P (stmt_info)) + { + if (vect_debug_details (NULL)) + fprintf (dump_file, "already marked relevant."); + return; + } + + STMT_VINFO_RELEVANT_P (stmt_info) = 1; + VARRAY_PUSH_TREE (worklist, stmt); +} + + +/* Function vect_stmt_relevant_p. + + Return true if STMT in loop that is represented by LOOP_VINFO is + "relevant for vectorization". + + A stmt is considered "relevant for vectorization" if: + - it has uses outside the loop. + - it has vdefs (it alters memory). + - control stmts in the loop (except for the exit condition). + + CHECKME: what other side effects would the vectorizer allow? */ + +static bool +vect_stmt_relevant_p (tree stmt, loop_vec_info loop_vinfo) +{ + v_may_def_optype v_may_defs; + v_must_def_optype v_must_defs; + struct loop *loop = LOOP_VINFO_LOOP (loop_vinfo); + int i; + dataflow_t df; + int num_uses; + + /* cond stmt other than loop exit cond. */ + if (is_ctrl_stmt (stmt) && (stmt != LOOP_VINFO_EXIT_COND (loop_vinfo))) + return true; + + /* changing memory. */ + v_may_defs = STMT_V_MAY_DEF_OPS (stmt); + v_must_defs = STMT_V_MUST_DEF_OPS (stmt); + if (v_may_defs || v_must_defs) + { + if (vect_debug_details (NULL)) + fprintf (dump_file, "vec_stmt_relevant_p: stmt has vdefs."); + return true; + } + + /* uses outside the loop. */ + df = get_immediate_uses (stmt); + num_uses = num_immediate_uses (df); + for (i = 0; i < num_uses; i++) + { + tree use = immediate_use (df, i); + basic_block bb = bb_for_stmt (use); + if (!flow_bb_inside_loop_p (loop, bb)) + { + if (vect_debug_details (NULL)) + fprintf (dump_file, "vec_stmt_relevant_p: used out of loop."); + return true; + } + } + + return false; +} + + +/* Function vect_mark_stmts_to_be_vectorized. + + Not all stmts in the loop need to be vectorized. For example: + + for i... + for j... + 1. T0 = i + j + 2. T1 = a[T0] + + 3. j = j + 1 + + Stmt 1 and 3 do not need to be vectorized, because loop control and + addressing of vectorized data-refs are handled differently. + + This pass detects such stmts. */ + +static bool +vect_mark_stmts_to_be_vectorized (loop_vec_info loop_vinfo) +{ + varray_type worklist; + struct loop *loop = LOOP_VINFO_LOOP (loop_vinfo); + basic_block *bbs = LOOP_VINFO_BBS (loop_vinfo); + unsigned int nbbs = loop->num_nodes; + block_stmt_iterator si; + tree stmt; + stmt_ann_t ann; + unsigned int i; + int j; + use_optype use_ops; + stmt_vec_info stmt_info; + + if (vect_debug_details (NULL)) + fprintf (dump_file, "\n<>\n"); + + VARRAY_TREE_INIT (worklist, 64, "work list"); + + /* 1. Init worklist. */ + + for (i = 0; i < nbbs; i++) + { + basic_block bb = bbs[i]; + for (si = bsi_start (bb); !bsi_end_p (si); bsi_next (&si)) + { + stmt = bsi_stmt (si); + + if (vect_debug_details (NULL)) + { + fprintf (dump_file, "init: stmt relevant? "); + print_generic_expr (dump_file, stmt, TDF_SLIM); + } + + stmt_info = vinfo_for_stmt (stmt); + STMT_VINFO_RELEVANT_P (stmt_info) = 0; + + if (vect_stmt_relevant_p (stmt, loop_vinfo)) + vect_mark_relevant (worklist, stmt); + } + } + + + /* 2. Process_worklist */ + + while (VARRAY_ACTIVE_SIZE (worklist) > 0) + { + stmt = VARRAY_TOP_TREE (worklist); + VARRAY_POP (worklist); + + if (vect_debug_details (NULL)) + { + fprintf (dump_file, "worklist: examine stmt: "); + print_generic_expr (dump_file, stmt, TDF_SLIM); + } + + /* Examine the USES in this statement. Mark all the statements which + feed this statement's uses as "relevant", unless the USE is used as + an array index. */ + + if (TREE_CODE (stmt) == PHI_NODE) + { + /* follow the def-use chain inside the loop. */ + for (j = 0; j < PHI_NUM_ARGS (stmt); j++) + { + tree arg = PHI_ARG_DEF (stmt, j); + tree def_stmt = NULL_TREE; + basic_block bb; + if (!vect_is_simple_use (arg, loop, &def_stmt)) + { + if (vect_debug_details (NULL)) + fprintf (dump_file, "worklist: unsupported use."); + varray_clear (worklist); + return false; + } + if (!def_stmt) + continue; + + if (vect_debug_details (NULL)) + { + fprintf (dump_file, "worklist: def_stmt: "); + print_generic_expr (dump_file, def_stmt, TDF_SLIM); + } + + bb = bb_for_stmt (def_stmt); + if (flow_bb_inside_loop_p (loop, bb)) + vect_mark_relevant (worklist, def_stmt); + } + } + + ann = stmt_ann (stmt); + use_ops = USE_OPS (ann); + + for (i = 0; i < NUM_USES (use_ops); i++) + { + tree use = USE_OP (use_ops, i); + + /* We are only interested in uses that need to be vectorized. Uses + that are used for address computation are not considered relevant. + */ + if (exist_non_indexing_operands_for_use_p (use, stmt)) + { + tree def_stmt = NULL_TREE; + basic_block bb; + if (!vect_is_simple_use (use, loop, &def_stmt)) + { + if (vect_debug_details (NULL)) + fprintf (dump_file, "worklist: unsupported use."); + varray_clear (worklist); + return false; + } + + if (!def_stmt) + continue; + + if (vect_debug_details (NULL)) + { + fprintf (dump_file, "worklist: examine use %d: ", i); + print_generic_expr (dump_file, use, TDF_SLIM); + } + + bb = bb_for_stmt (def_stmt); + if (flow_bb_inside_loop_p (loop, bb)) + vect_mark_relevant (worklist, def_stmt); + } + } + } /* while worklist */ + + varray_clear (worklist); + return true; +} + + +/* Function vect_get_loop_niters. + + Determine how many iterations the loop is executed. */ + +static tree +vect_get_loop_niters (struct loop *loop, HOST_WIDE_INT *number_of_iterations) +{ + tree niters; + + if (vect_debug_details (NULL)) + fprintf (dump_file, "\n<>\n"); + + niters = number_of_iterations_in_loop (loop); + + if (niters != NULL_TREE + && niters != chrec_dont_know + && host_integerp (niters,0)) + { + *number_of_iterations = TREE_INT_CST_LOW (niters); + + if (vect_debug_details (NULL)) + fprintf (dump_file, "==> get_loop_niters:" HOST_WIDE_INT_PRINT_DEC, + *number_of_iterations); + } + + return get_loop_exit_condition (loop); +} + + +/* Function vect_analyze_loop_form. + + Verify the following restrictions (some may be relaxed in the future): + - it's an inner-most loop + - number of BBs = 2 (which are the loop header and the latch) + - the loop has a pre-header + - the loop has a single entry and exit + - the loop exit condition is simple enough, and the number of iterations + can be analyzed (a countable loop). */ + +static loop_vec_info +vect_analyze_loop_form (struct loop *loop) +{ + loop_vec_info loop_vinfo; + tree loop_cond; + HOST_WIDE_INT number_of_iterations = -1; + + if (vect_debug_details (loop)) + fprintf (dump_file, "\n<>\n"); + + if (loop->level > 1 /* FORNOW: inner-most loop */ + || loop->num_exits > 1 || loop->num_entries > 1 || loop->num_nodes != 2 + || !loop->pre_header || !loop->header || !loop->latch) + { + if (vect_debug_stats (loop) || vect_debug_details (loop)) + { + fprintf (dump_file, "not vectorized: bad loop form. "); + if (loop->level > 1) + fprintf (dump_file, "nested loop."); + else if (loop->num_exits > 1 || loop->num_entries > 1) + fprintf (dump_file, "multiple entries or exits."); + else if (loop->num_nodes != 2 || !loop->header || !loop->latch) + fprintf (dump_file, "too many BBs in loop."); + else if (!loop->pre_header) + fprintf (dump_file, "no pre-header BB for loop."); + } + + return NULL; + } + + /* We assume that the loop exit condition is at the end of the loop. i.e, + that the loop is represented as a do-while (with a proper if-guard + before the loop if needed), where the loop header contains all the + executable statements, and the latch is empty. */ + if (!empty_block_p (loop->latch)) + { + if (vect_debug_stats (loop) || vect_debug_details (loop)) + fprintf (dump_file, "not vectorized: unexpectd loop form."); + return NULL; + } + + if (empty_block_p (loop->header)) + { + if (vect_debug_stats (loop) || vect_debug_details (loop)) + fprintf (dump_file, "not vectorized: empty loop."); + return NULL; + } + + loop_cond = vect_get_loop_niters (loop, &number_of_iterations); + if (!loop_cond) + { + if (vect_debug_stats (loop) || vect_debug_details (loop)) + fprintf (dump_file, "not vectorized: complicated exit condition."); + return NULL; + } + + if (number_of_iterations < 0) + { + if (vect_debug_stats (loop) || vect_debug_details (loop)) + fprintf (dump_file, "not vectorized: unknown loop bound."); + return NULL; + } + + if (number_of_iterations == 0) /* CHECKME: can this happen? */ + { + if (vect_debug_stats (loop) || vect_debug_details (loop)) + fprintf (dump_file, "not vectorized: number of iterations = 0."); + return NULL; + } + + loop_vinfo = new_loop_vec_info (loop); + LOOP_VINFO_EXIT_COND (loop_vinfo) = loop_cond; + LOOP_VINFO_NITERS (loop_vinfo) = number_of_iterations; + + return loop_vinfo; +} + + +/* Function vect_analyze_loop. + + Apply a set of analyses on LOOP, and create a loop_vec_info struct + for it. The different analyses will record information in the + loop_vec_info struct. */ + +static loop_vec_info +vect_analyze_loop (struct loop *loop) +{ + bool ok; + loop_vec_info loop_vinfo; + + if (vect_debug_details (NULL)) + fprintf (dump_file, "\n<<<<<<< analyze_loop_nest >>>>>>>\n"); + + /* Check the CFG characteristics of the loop (nesting, entry/exit, etc. */ + + loop_vinfo = vect_analyze_loop_form (loop); + if (!loop_vinfo) + { + if (vect_debug_details (loop)) + fprintf (dump_file, "bad loop form."); + return NULL; + } + + /* Find all data references in the loop (which correspond to vdefs/vuses) + and analyze their evolution in the loop. + + FORNOW: Handle only simple, one-dimensional, array references, which + alignment can be forced, and aligned pointer-references. */ + + ok = vect_analyze_data_refs (loop_vinfo); + if (!ok) + { + if (vect_debug_details (loop)) + fprintf (dump_file, "bad data references."); + destroy_loop_vec_info (loop_vinfo); + return NULL; + } + + + /* Data-flow analysis to detect stmts that do not need to be vectorized. */ + + ok = vect_mark_stmts_to_be_vectorized (loop_vinfo); + if (!ok) + { + if (vect_debug_details (loop)) + fprintf (dump_file, "unexpected pattern."); + if (vect_debug_details (loop)) + fprintf (dump_file, "not vectorized: unexpected pattern."); + destroy_loop_vec_info (loop_vinfo); + return NULL; + } + + + /* Check that all cross-iteration scalar data-flow cycles are OK. + Cross-iteration cycles caused by virtual phis are analyzed separately. */ + + ok = vect_analyze_scalar_cycles (loop_vinfo); + if (!ok) + { + if (vect_debug_details (loop)) + fprintf (dump_file, "bad scalar cycle."); + destroy_loop_vec_info (loop_vinfo); + return NULL; + } + + + /* Analyze data dependences between the data-refs in the loop. + FORNOW: fail at the first data dependence that we encounter. */ + + ok = vect_analyze_data_ref_dependences (loop_vinfo); + if (!ok) + { + if (vect_debug_details (loop)) + fprintf (dump_file, "bad data dependence."); + destroy_loop_vec_info (loop_vinfo); + return NULL; + } + + + /* Analyze the access patterns of the data-refs in the loop (consecutive, + complex, etc.). FORNOW: Only handle consecutive access pattern. */ + + ok = vect_analyze_data_ref_accesses (loop_vinfo); + if (!ok) + { + if (vect_debug_details (loop)) + fprintf (dump_file, "bad data access."); + destroy_loop_vec_info (loop_vinfo); + return NULL; + } + + + /* Analyze the alignment of the data-refs in the loop. + FORNOW: Only aligned accesses are handled. */ + + ok = vect_analyze_data_refs_alignment (loop_vinfo); + if (!ok) + { + if (vect_debug_details (loop)) + fprintf (dump_file, "bad data alignment."); + destroy_loop_vec_info (loop_vinfo); + return NULL; + } + + + /* Scan all the operations in the loop and make sure they are + vectorizable. */ + + ok = vect_analyze_operations (loop_vinfo); + if (!ok) + { + if (vect_debug_details (loop)) + fprintf (dump_file, "bad operation or unsupported loop bound."); + destroy_loop_vec_info (loop_vinfo); + return NULL; + } + + LOOP_VINFO_VECTORIZABLE_P (loop_vinfo) = 1; + + return loop_vinfo; +} + + +/* Function need_imm_uses_for. + + Return whether we ought to include information for 'var' + when calculating immediate uses. For this pass we only want use + information for non-virtual variables. */ + +static bool +need_imm_uses_for (tree var) +{ + return is_gimple_reg (var); +} + + +/* Function vectorize_loops. + + Entry Point to loop vectorization phase. */ + +void +vectorize_loops (struct loops *loops) +{ + unsigned int i, loops_num; + unsigned int num_vectorized_loops = 0; + + /* Does the target support SIMD? */ + /* FORNOW: until more sophisticated machine modelling is in place. */ + if (!UNITS_PER_SIMD_WORD) + { + if (vect_debug_details (NULL)) + fprintf (dump_file, "vectorizer: target vector size is not defined."); + return; + } + + compute_immediate_uses (TDFA_USE_OPS, need_imm_uses_for); + + /* ----------- Analyze loops. ----------- */ + + /* If some loop was duplicated, it gets bigger number + than all previously defined loops. This fact allows us to run + only over initial loops skipping newly generated ones. */ + loops_num = loops->num; + for (i = 1; i < loops_num; i++) + { + loop_vec_info loop_vinfo; + struct loop *loop = loops->parray[i]; + + if (!loop) + continue; + + flow_loop_scan (loop, LOOP_ALL); + + loop_vinfo = vect_analyze_loop (loop); + loop->aux = loop_vinfo; + + if (!loop_vinfo || !LOOP_VINFO_VECTORIZABLE_P (loop_vinfo)) + continue; + + vect_transform_loop (loop_vinfo, loops); + num_vectorized_loops++; + } + + if (vect_debug_stats (NULL) || vect_debug_details (NULL)) + fprintf (dump_file, "\nvectorized %u loops in function.\n", + num_vectorized_loops); + + /* ----------- Finalize. ----------- */ + + free_df (); + for (i = 1; i < loops_num; i++) + { + struct loop *loop = loops->parray[i]; + loop_vec_info loop_vinfo = loop->aux; + if (!loop) + continue; + destroy_loop_vec_info (loop_vinfo); + loop->aux = NULL; + } + + loop_commit_inserts (); + rewrite_into_ssa (false); + if (bitmap_first_set_bit (vars_to_rename) >= 0) + { + /* The rewrite of ssa names may cause violation of loop closed ssa + form invariants. TODO -- avoid these rewrites completely. + Information in virtual phi nodes is sufficient for it. */ + rewrite_into_loop_closed_ssa (); + } + bitmap_clear (vars_to_rename); +} diff --git a/gcc/tree-vectorizer.h b/gcc/tree-vectorizer.h new file mode 100644 index 00000000000..4c280e93415 --- /dev/null +++ b/gcc/tree-vectorizer.h @@ -0,0 +1,181 @@ +/* Loop Vectorization + Copyright (C) 2003, 2004 Free Software Foundation, Inc. + Contributed by Dorit Naishlos + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +GCC is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING. If not, write to the Free +Software Foundation, 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ + +#ifndef GCC_TREE_VECTORIZER_H +#define GCC_TREE_VECTORIZER_H + +/* Used for naming of new temporaries. */ +enum vect_var_kind { + vect_simple_var, + vect_pointer_var +}; + +/* Defines type of operation: unary or binary. */ +enum operation_type { + unary_op = 1, + binary_op +}; + +/*-----------------------------------------------------------------*/ +/* Info on vectorized defs. */ +/*-----------------------------------------------------------------*/ +enum stmt_vec_info_type { + undef_vec_info_type = 0, + load_vec_info_type, + store_vec_info_type, + op_vec_info_type, + assignment_vec_info_type +}; + +typedef struct _stmt_vec_info { + + enum stmt_vec_info_type type; + + /* The stmt to which this info struct refers to. */ + tree stmt; + + /* The loop with resprct to which STMT is vectorized. */ + struct loop *loop; + + /* Not all stmts in the loop need to be vectorized. e.g, the incrementation + of the loop induction variable and computation of array indexes. relevant + indicates whether the stmt needs to be vectorized. */ + bool relevant; + + /* The vector type to be used. */ + tree vectype; + + /* The vectorized version of the stmt. */ + tree vectorized_stmt; + + + /** The following is relevant only for stmts that contain a non-scalar + data-ref (array/pointer/struct access). A GIMPLE stmt is expected to have + at most one such data-ref. **/ + + /* Information about the data-ref (access function, etc). */ + struct data_reference *data_ref_info; + + /* Aliasing information. */ + tree memtag; +} *stmt_vec_info; + +/* Access Functions. */ +#define STMT_VINFO_TYPE(S) (S)->type +#define STMT_VINFO_STMT(S) (S)->stmt +#define STMT_VINFO_LOOP(S) (S)->loop +#define STMT_VINFO_RELEVANT_P(S) (S)->relevant +#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 + +static inline void set_stmt_info (stmt_ann_t ann, stmt_vec_info stmt_info); +static inline stmt_vec_info vinfo_for_stmt (tree stmt); + +static inline void +set_stmt_info (stmt_ann_t ann, stmt_vec_info stmt_info) +{ + if (ann) + ann->common.aux = (char *) stmt_info; +} + +static inline stmt_vec_info +vinfo_for_stmt (tree stmt) +{ + stmt_ann_t ann = stmt_ann (stmt); + return ann ? (stmt_vec_info) ann->common.aux : NULL; +} + +/*-----------------------------------------------------------------*/ +/* Info on data references alignment. */ +/*-----------------------------------------------------------------*/ + +#define DR_MISALIGNMENT(DR) (DR)->aux + +static inline bool +aligned_access_p (struct data_reference *data_ref_info) +{ + return (DR_MISALIGNMENT (data_ref_info) == 0); +} + +static inline bool +unknown_alignment_for_access_p (struct data_reference *data_ref_info) +{ + return (DR_MISALIGNMENT (data_ref_info) == -1); +} + + +/*-----------------------------------------------------------------*/ +/* Info on vectorized loops. */ +/*-----------------------------------------------------------------*/ +typedef struct _loop_vec_info { + + /* The loop to which this info struct refers to. */ + struct loop *loop; + + /* The loop basic blocks. */ + basic_block *bbs; + + /* The loop exit_condition. */ + tree exit_cond; + + /* Number of iterations. -1 if unknown. */ + HOST_WIDE_INT num_iters; + + /* Is the loop vectorizable? */ + bool vectorizable; + + /* Unrolling factor */ + int vectorization_factor; + + /* All data references in the loop that are being written to. */ + varray_type data_ref_writes; + + /* All data references in the loop that are being read from. */ + varray_type data_ref_reads; +} *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_NITERS_KNOWN_P(L) ((L)->num_iters > 0) + +/*-----------------------------------------------------------------*/ +/* Function prototypes. */ +/*-----------------------------------------------------------------*/ + +/* Main driver. */ +extern void vectorize_loops (struct loops *); + +/* creation and deletion of loop and stmt info structs. */ +extern loop_vec_info new_loop_vec_info (struct loop *loop); +extern void destroy_loop_vec_info (loop_vec_info); +extern stmt_vec_info new_stmt_vec_info (tree stmt, struct loop *loop); + +#endif /* GCC_TREE_VECTORIZER_H */