Commit 6775f1f3 by Ira Rosen Committed by Dorit Nuzman

tree-vectorizer.h (stmt_vec_info): Add vect_dr_base field.

2004-09-19  Ira Rosen  <irar@il.ibm.com>

        * tree-vectorizer.h (stmt_vec_info): Add vect_dr_base field.
        (STMT_VINFO_VECT_DR_BASE): Declare.
        (VECT_SMODULO): Declare.
        * tree-vectorizer.c (vect_compute_array_ref_alignment): New function.
        (vect_compute_array_base_alignment): New function.
        (vect_analyze_data_ref_access): Check array indices. Remove one
        dimensional arrays restriction.
        (vect_get_ptr_offset): New function.
        (vect_get_symbl_and_dr): New function.
        (vect_get_base_and_bit_offset): Support additional data refs. Renamed
        (former name vect_get_base_decl_and_bit_offset).
        (vect_create_index_for_array_ref): Removed.
        (vect_create_index_for_vector_ref): New function.
        (vect_create_addr_base_for_vector_ref): New function.
        (vect_create_data_ref): Handle additional data refs. Call
        vect_create_index_for_vector_ref and vect_create_addr_base_for_vector_ref.
        (vect_compute_data_ref_alignment): Support the changes. Call
        vect_get_base_and_bit_offset.
        (vect_analyze_data_refs): Call vect_get_symbl_and_dr. Support additional
        data refs. Store vect_dr_base.
        (vect_analyze_data_ref_accesses): Support nonconstant init.
        (new_stmt_vec_info): Initialize vect_dr_base field.
        (vect_is_simple_iv_evolution): Call initial_condition_in_loop_num.
        (get_vectype_for_scalar_type): Check for BLKmode.
        * tree-chrec.h (initial_condition_in_loop_num): Declare.
        * tree-chrec.c (initial_condition_in_loop_num): New function.
        (chrec_component_in_loop_num): New function.
        (evolution_part_in_loop_num): Call chrec_component_in_loop_num.
        * tree-data-ref.c (analyze_array_indexes): Change parameter (access_fns)
        to be pointer to varray_type.

From-SVN: r87731
parent 15db5571
2004-09-19 Ira Rosen <irar@il.ibm.com>
* tree-vectorizer.h (stmt_vec_info): Add vect_dr_base field.
(STMT_VINFO_VECT_DR_BASE): Declare.
(VECT_SMODULO): Declare.
* tree-vectorizer.c (vect_compute_array_ref_alignment): New function.
(vect_compute_array_base_alignment): New function.
(vect_analyze_data_ref_access): Check array indices. Remove one
dimensional arrays restriction.
(vect_get_ptr_offset): New function.
(vect_get_symbl_and_dr): New function.
(vect_get_base_and_bit_offset): Support additional data refs. Renamed
(former name vect_get_base_decl_and_bit_offset).
(vect_create_index_for_array_ref): Removed.
(vect_create_index_for_vector_ref): New function.
(vect_create_addr_base_for_vector_ref): New function.
(vect_create_data_ref): Handle additional data refs. Call
vect_create_index_for_vector_ref and vect_create_addr_base_for_vector_ref.
(vect_compute_data_ref_alignment): Support the changes. Call
vect_get_base_and_bit_offset.
(vect_analyze_data_refs): Call vect_get_symbl_and_dr. Support additional
data refs. Store vect_dr_base.
(vect_analyze_data_ref_accesses): Support nonconstant init.
(new_stmt_vec_info): Initialize vect_dr_base field.
(vect_is_simple_iv_evolution): Call initial_condition_in_loop_num.
(get_vectype_for_scalar_type): Check for BLKmode.
* tree-chrec.h (initial_condition_in_loop_num): Declare.
* tree-chrec.c (initial_condition_in_loop_num): New function.
(chrec_component_in_loop_num): New function.
(evolution_part_in_loop_num): Call chrec_component_in_loop_num.
* tree-data-ref.c (analyze_array_indexes): Change parameter (access_fns)
to be pointer to varray_type.
2004-09-19 Jan Hubicka <jh@suse.cz>
* basic-block.h (update_bb_profile_after_threading): Declare.
......
2004-09-19 Ira Rosen <irar@il.ibm.com>
* gcc.dg/vect/vect-13.c: Now vectorized on ppc*.
* gcc.dg/vect/vect-73.c: New testcase.
* gcc.dg/vect/vect-74.c: New testcase.
* gcc.dg/vect/vect-75.c: New testcase.
* gcc.dg/vect/vect-76.c: New testcase.
* gcc.dg/vect/vect-77.c: New testcase.
* gcc.dg/vect/vect-78.c: New testcase
2004-09-18 Paul Brook <paul@codesourcery.com>
* g++.old-deja/g++.pt/static11.C: XFAIL on arm*-*-eabi.
......
......@@ -22,4 +22,4 @@ int main ()
return 0;
}
/* { dg-final { scan-tree-dump-times "vectorized 1 loops" 1 "vect" { xfail *-*-* } } } */
/* { dg-final { scan-tree-dump-times "vectorized 1 loops" 1 "vect" } } */
/* { 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 <stdarg.h>
#include "tree-vect.h"
#define N 16
int ic[N*2];
#define ia (ic+N)
int main1 ()
{
int i, j;
int ib[N] = {0,3,6,9,12,15,18,21,24,27,30,33,36,39,42,45};
for (i = 0; i < N; i++)
{
ia[i] = ib[i];
}
/* check results: */
for (i = 0; i < N; i++)
{
if (ia[i] != ib[i])
abort();
}
return 0;
}
int main (void)
{
check_vect ();
return main1 ();
}
/* { dg-final { scan-tree-dump-times "vectorized 1 loops" 1 "vect" } } */
/* { 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 <stdarg.h>
#include "tree-vect.h"
#define N 16
typedef float afloat __attribute__ ((__aligned__(16)));
afloat a[N];
afloat b[N+4] = {0.2, 1.3, 2.3, 3.4, 4.5, 5.6, 7.8, 9.0, 10.11, 11.12, 12.13, 13.14, 14.15, 15.16, 16.17, 17.18, 18.19, 19.20};
afloat c[N] = {0.2, 1.3, 2.3, 3.4, 4.5, 5.6, 7.8, 9.0, 10.11, 11.12, 12.13, 13.14, 14.15, 15.16};
float fa[N];
float fb[N+4] = {0.2, 1.3, 2.3, 3.4, 4.5, 5.6, 7.8, 9.0, 10.11, 11.12, 12.13, 13.14, 14.15, 15.16,
16.17, 17.18, 18.19, 19.20};
float fc[N] = {0.2, 1.3, 2.3, 3.4, 4.5, 5.6, 7.8, 9.0, 10.11, 11.12, 12.13, 13.14, 14.15, 15.16};
int
main1 (afloat *__restrict__ pa, afloat * __restrict__ pb, afloat * __restrict__ pc)
{
int i;
afloat *q = pb + 4;
for (i = 0; i < N; i++)
{
pa[i] = q[i] * pc[i];
}
for (i = 0; i < N; i++)
{
if (pa[i] != q[i] * pc[i])
abort();
}
return 0;
}
/* Not vectorizable. Alias. */
int
main2 (afloat *pa, afloat *pb, afloat *pc)
{
int i;
afloat *q = pb + 4;
for (i = 0; i < N; i++)
{
pa[i] = q[i] * pc[i];
}
for (i = 0; i < N; i++)
{
if (pa[i] != q[i] * pc[i])
abort();
}
return 0;
}
/* Not vectorizable: not aligned pointers. */
int
main3 (float * __restrict__ pa, float * __restrict__ pb, float *__restrict__ pc)
{
int i;
afloat *q = pb + 4;
for (i = 0; i < N; i++)
{
pa[i] = q[i] * pc[i];
}
for (i = 0; i < N; i++)
{
if (pa[i] != q[i] * pc[i])
abort();
}
return 0;
}
int main (void)
{
check_vect ();
main1 (a, b, c);
main2 (a, b, c);
main3 (fa, fb, fc);
return 0;
}
/* { dg-final { scan-tree-dump-times "vectorized 1 loops" 1 "vect" } } */
/* { dg-final { scan-tree-dump-times "vectorized 0 loops" 2 "vect" } } */
/* { 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 <stdarg.h>
#include "tree-vect.h"
#define N 8
#define OFF 8
typedef int aint __attribute__ ((__aligned__(16)));
aint ib[N+OFF] = {0, 1, 3, 5, 7, 11, 13, 17, 0, 2, 6, 10, 14, 22, 26, 34};
int main1 (aint *ib)
{
int i;
int ia[N];
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 (ib);
return 0;
}
/* { dg-final { scan-tree-dump-times "vectorized 1 loops" 1 "vect" } } */
/* { 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 <stdarg.h>
#include "tree-vect.h"
#define N 8
#define OFF 4
typedef int aint __attribute__ ((__aligned__(16)));
aint ib[N+OFF] = {0, 1, 3, 5, 7, 11, 13, 17, 0, 2, 6, 10};
int main1 (aint *pib)
{
int i;
int ia[N+OFF];
int ic[N+OFF] = {0, 1, 3, 5, 7, 11, 13, 17, 0, 2, 6, 10};
for (i = OFF; i < N; i++)
{
ia[i] = pib[i - OFF];
}
/* check results: */
for (i = OFF; i < N; i++)
{
if (ia[i] != pib[i - OFF])
abort ();
}
for (i = 0; i < N; i++)
{
ia[i] = pib[i - OFF];
}
/* check results: */
for (i = 0; i < N; i++)
{
if (ia[i] != pib[i - OFF])
abort ();
}
for (i = OFF; i < N; i++)
{
ia[i] = ic[i - OFF];
}
/* check results: */
for (i = OFF; i < N; i++)
{
if (ia[i] != ic[i - OFF])
abort ();
}
return 0;
}
int main (void)
{
check_vect ();
main1 (&ib[OFF]);
return 0;
}
/* { dg-final { scan-tree-dump-times "vectorized 3 loops" 1 "vect" } } */
/* { 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 <stdarg.h>
#include "tree-vect.h"
#define N 8
#define OFF 8
typedef int aint __attribute__ ((__aligned__(16)));
aint ib[N+OFF] = {0, 1, 3, 5, 7, 11, 13, 17, 0, 2, 6, 10, 14, 22, 26, 34};
int main1 (aint *ib, int off)
{
int i;
int ia[N];
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 (ib, 8);
return 0;
}
/* { dg-final { scan-tree-dump-times "vectorized 1 loops" 1 "vect" { xfail *-*-* } } } */
/* { 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 <stdarg.h>
#include "tree-vect.h"
#define N 8
#define OFF 8
typedef int aint __attribute__ ((__aligned__(16)));
aint ib[N+OFF] = {0, 1, 3, 5, 7, 11, 13, 17, 0, 2, 6, 10, 14, 22, 26, 34};
int off = 8;
int main1 (aint *ib)
{
int i;
int ia[N];
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 (ib);
return 0;
}
/* { dg-final { scan-tree-dump-times "vectorized 1 loops" 1 "vect" { xfail *-*-* } } } */
......@@ -583,14 +583,16 @@ hide_evolution_in_other_loops_than_loop (tree chrec,
}
}
/* Returns the evolution part in LOOP_NUM. Example: the call
get_evolution_in_loop (1, {{0, +, 1}_1, +, 2}_1) returns
{1, +, 2}_1 */
/* Returns the evolution part of CHREC in LOOP_NUM when RIGHT is
true, otherwise returns the initial condition in LOOP_NUM. */
tree
evolution_part_in_loop_num (tree chrec,
unsigned loop_num)
static tree
chrec_component_in_loop_num (tree chrec,
unsigned loop_num,
bool right)
{
tree component;
if (automatically_generated_chrec_p (chrec))
return chrec;
......@@ -599,15 +601,22 @@ evolution_part_in_loop_num (tree chrec,
case POLYNOMIAL_CHREC:
if (CHREC_VARIABLE (chrec) == loop_num)
{
if (right)
component = CHREC_RIGHT (chrec);
else
component = CHREC_LEFT (chrec);
if (TREE_CODE (CHREC_LEFT (chrec)) != POLYNOMIAL_CHREC
|| CHREC_VARIABLE (CHREC_LEFT (chrec)) != CHREC_VARIABLE (chrec))
return CHREC_RIGHT (chrec);
return component;
else
return build_polynomial_chrec
(loop_num,
evolution_part_in_loop_num (CHREC_LEFT (chrec), loop_num),
CHREC_RIGHT (chrec));
chrec_component_in_loop_num (CHREC_LEFT (chrec),
loop_num,
right),
component);
}
else if (CHREC_VARIABLE (chrec) < loop_num)
......@@ -615,13 +624,40 @@ evolution_part_in_loop_num (tree chrec,
return NULL_TREE;
else
return evolution_part_in_loop_num (CHREC_LEFT (chrec), loop_num);
return chrec_component_in_loop_num (CHREC_LEFT (chrec),
loop_num,
right);
default:
if (right)
return NULL_TREE;
else
return chrec;
}
}
/* Returns the evolution part in LOOP_NUM. Example: the call
evolution_part_in_loop_num (1, {{0, +, 1}_1, +, 2}_1) returns
{1, +, 2}_1 */
tree
evolution_part_in_loop_num (tree chrec,
unsigned loop_num)
{
return chrec_component_in_loop_num (chrec, loop_num, true);
}
/* Returns the initial condition in LOOP_NUM. Example: the call
initial_condition_in_loop_num ({{0, +, 1}_1, +, 2}_2, 1) returns
{0, +, 1}_1 */
tree
initial_condition_in_loop_num (tree chrec,
unsigned loop_num)
{
return chrec_component_in_loop_num (chrec, loop_num, false);
}
/* Set or reset the evolution of CHREC to NEW_EVOL in loop LOOP_NUM.
This function is essentially used for setting the evolution to
chrec_dont_know, for example after having determined that it is
......
......@@ -76,6 +76,7 @@ extern tree chrec_apply (unsigned, tree, tree);
extern tree chrec_replace_initial_condition (tree, tree);
extern tree update_initial_condition_to_origin (tree);
extern tree initial_condition (tree);
extern tree initial_condition_in_loop_num (tree, unsigned);
extern tree evolution_part_in_loop_num (tree, unsigned);
extern tree hide_evolution_in_other_loops_than_loop (tree, unsigned);
extern tree reset_evolution_in_loop (unsigned, tree, tree);
......
......@@ -498,7 +498,7 @@ dump_data_dependence_direction (FILE *file,
static tree
analyze_array_indexes (struct loop *loop,
varray_type access_fns,
varray_type *access_fns,
tree ref)
{
tree opnd0, opnd1;
......@@ -514,7 +514,7 @@ analyze_array_indexes (struct loop *loop,
access_fn = instantiate_parameters
(loop, analyze_scalar_evolution (loop, opnd1));
VARRAY_PUSH_TREE (access_fns, access_fn);
VARRAY_PUSH_TREE (*access_fns, access_fn);
/* Recursively record other array access functions. */
if (TREE_CODE (opnd0) == ARRAY_REF)
......@@ -549,7 +549,7 @@ analyze_array (tree stmt, tree ref, bool is_read)
DR_REF (res) = ref;
VARRAY_TREE_INIT (DR_ACCESS_FNS (res), 3, "access_fns");
DR_BASE_NAME (res) = analyze_array_indexes
(loop_containing_stmt (stmt), DR_ACCESS_FNS (res), ref);
(loop_containing_stmt (stmt), &(DR_ACCESS_FNS (res)), ref);
DR_IS_READ (res) = is_read;
if (dump_file && (dump_flags & TDF_DETAILS))
......
......@@ -57,10 +57,9 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
data: scalars (which are represented by SSA_NAMES), and memory references
("data-refs"). These two types of data require different handling both
during analysis and transformation. The types of data-refs that the
vectorizer currently supports are ARRAY_REFS that are one dimensional
arrays which base is an array DECL (not a pointer), and INDIRECT_REFS
through pointers; both array and pointer accesses are required to have a
simple (consecutive) access pattern.
vectorizer currently supports are ARRAY_REFS which base is an array DECL
(not a pointer), and INDIRECT_REFS through pointers; both array and pointer
accesses are required to have a simple (consecutive) access pattern.
Analysis phase:
===============
......@@ -175,18 +174,28 @@ 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
static bool 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);
static tree vect_get_base_and_bit_offset
(struct data_reference *, tree, tree, loop_vec_info, tree *, bool*);
static struct data_reference * vect_analyze_pointer_ref_access
(tree, tree, bool);
static tree vect_compute_array_base_alignment (tree, tree, tree *, tree *);
static tree vect_compute_array_ref_alignment
(struct data_reference *, loop_vec_info, tree, tree *);
static tree vect_get_ptr_offset (tree, tree, tree *);
static tree vect_get_symbl_and_dr
(tree, tree, bool, loop_vec_info, struct data_reference **);
/* 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 vect_create_index_for_vector_ref (struct loop *, block_stmt_iterator *);
static tree vect_create_addr_base_for_vector_ref (tree, tree *);
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);
......@@ -221,6 +230,7 @@ new_stmt_vec_info (tree stmt, struct loop *loop)
STMT_VINFO_VEC_STMT (res) = NULL;
STMT_VINFO_DATA_REF (res) = NULL;
STMT_VINFO_MEMTAG (res) = NULL;
STMT_VINFO_VECT_DR_BASE (res) = NULL;
return res;
}
......@@ -402,55 +412,187 @@ vect_debug_details (struct loop *loop)
return false;
}
/* 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). */
/* Function vect_get_ptr_offset
Compute the OFFSET modulo vector-type alignment of pointer REF in bits. */
static tree
vect_get_ptr_offset (tree ref ATTRIBUTE_UNUSED,
tree vectype ATTRIBUTE_UNUSED,
tree *offset ATTRIBUTE_UNUSED)
{
/* TODO: Use alignment information. */
return NULL_TREE;
}
/* Function vect_get_base_and_bit_offset
Return the BASE of the data reference EXPR.
If VECTYPE is given, also compute the OFFSET from BASE in bits.
E.g., for EXPR a.b[i] + 4B, BASE is a, and OFFSET is the overall offset in
bits of 'a.b[i] + 4B' from a.
Input:
EXPR - the memory reference that is being analyzed
DR - the data_reference struct of the _original_ memory reference
(Note: DR_REF (DR) is not necessarily EXPR)
VECTYPE - the type that defines the alignment (i.e, we compute
alignment relative to TYPE_ALIGN(VECTYPE))
Output:
BASE (returned value) - the base of the data reference EXPR.
E.g, if EXPR is a.b[k].c[i][j] the returned
base is a.
OFFSET - offset of EXPR from BASE in bits
BASE_ALIGNED_P - indicates if BASE is aligned
If something unexpected is encountered (an unsupported form of data-ref),
or if VECTYPE is given but OFFSET cannot be determined:
then NULL_TREE is returned. */
static tree
vect_get_base_decl_and_bit_offset (tree ref, tree *offset)
vect_get_base_and_bit_offset (struct data_reference *dr,
tree expr,
tree vectype,
loop_vec_info loop_vinfo,
tree *offset,
bool *base_aligned_p)
{
tree decl;
if (TREE_CODE (ref) == VAR_DECL)
return ref;
tree this_offset = size_zero_node;
tree base = NULL_TREE;
tree next_ref;
tree oprnd0, oprnd1;
struct data_reference *array_dr;
enum tree_code code = TREE_CODE (expr);
if (TREE_CODE (ref) == COMPONENT_REF)
*base_aligned_p = false;
switch (code)
{
tree this_offset;
tree oprnd0 = TREE_OPERAND (ref, 0);
tree oprnd1 = TREE_OPERAND (ref, 1);
/* These cases end the recursion: */
case VAR_DECL:
*offset = size_zero_node;
if (vectype && DECL_ALIGN (expr) >= TYPE_ALIGN (vectype))
*base_aligned_p = true;
return expr;
case SSA_NAME:
if (!vectype)
return expr;
if (TREE_CODE (TREE_TYPE (expr)) != POINTER_TYPE)
return NULL_TREE;
if (TYPE_ALIGN (TREE_TYPE (TREE_TYPE (expr))) < TYPE_ALIGN (vectype))
{
base = vect_get_ptr_offset (expr, vectype, offset);
if (base)
*base_aligned_p = true;
}
else
{
*base_aligned_p = true;
*offset = size_zero_node;
base = expr;
}
return base;
case INTEGER_CST:
*offset = int_const_binop (MULT_EXPR, expr,
build_int_cst (NULL_TREE, BITS_PER_UNIT), 1);
return expr;
/* These cases continue the recursion: */
case COMPONENT_REF:
oprnd0 = TREE_OPERAND (expr, 0);
oprnd1 = TREE_OPERAND (expr, 1);
this_offset = bit_position (oprnd1);
if (!host_integerp (this_offset,1))
if (vectype && !host_integerp (this_offset, 1))
return NULL_TREE;
next_ref = oprnd0;
break;
case ADDR_EXPR:
oprnd0 = TREE_OPERAND (expr, 0);
next_ref = oprnd0;
break;
case INDIRECT_REF:
oprnd0 = TREE_OPERAND (expr, 0);
next_ref = oprnd0;
break;
decl = vect_get_base_decl_and_bit_offset (oprnd0, offset);
case ARRAY_REF:
if (DR_REF (dr) != expr)
/* Build array data_reference struct if the existing DR_REF
doesn't match EXPR. This happens, for example, when the
EXPR is *T and T is initialized to &arr[indx]. The DR struct
contains information on the access of T, not of arr. In order
to continue the analysis, we create a new DR struct that
describes the access of arr.
*/
array_dr = analyze_array (DR_STMT (dr), expr, DR_IS_READ (dr));
else
array_dr = dr;
if (decl)
next_ref = vect_compute_array_ref_alignment (array_dr, loop_vinfo,
vectype, &this_offset);
if (!next_ref)
return NULL_TREE;
if (vectype &&
TYPE_ALIGN (TREE_TYPE (TREE_TYPE (next_ref))) >= TYPE_ALIGN (vectype))
{
*offset = int_const_binop (PLUS_EXPR, *offset, this_offset, 1);
*offset = this_offset;
*base_aligned_p = true;
return next_ref;
}
break;
case PLUS_EXPR:
case MINUS_EXPR:
/* In case we have a PLUS_EXPR of the form
(oprnd0 + oprnd1), we assume that only oprnd0 determines the base.
This is verified in vect_get_symbl_and_dr. */
oprnd0 = TREE_OPERAND (expr, 0);
oprnd1 = TREE_OPERAND (expr, 1);
base = vect_get_base_and_bit_offset
(dr, oprnd1, vectype, loop_vinfo, &this_offset, base_aligned_p);
if (vectype && !base)
return NULL_TREE;
if (!host_integerp (*offset,1) || TREE_OVERFLOW (*offset))
next_ref = oprnd0;
break;
default:
return NULL_TREE;
}
base = vect_get_base_and_bit_offset (dr, next_ref, vectype,
loop_vinfo, offset, base_aligned_p);
if (vectype && base)
{
*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);
print_generic_expr (dump_file, expr, 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;
return base;
}
/* Function vect_force_dr_alignment_p.
Returns whether the alignment of a DECL can be forced to be aligned
......@@ -507,87 +649,164 @@ vect_get_new_vect_var (tree type, enum vect_var_kind var_kind, const char *name)
}
/* Function create_index_for_array_ref.
/* Function vect_create_index_for_vector_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.
LOOP: The loop being vectorized.
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. */
Output:
Return an index that will be used to index a vector array. It is expected
that a pointer to the first vector will be used as the base address for the
indexed reference.
FORNOW: we are not trying to be efficient, just creating a new index each
time from scratch. At this time all vector references could use the same
index.
TODO: create only one index to be used by all vector references. Record
the index in the LOOP_VINFO the first time this procedure is called and
return it on subsequent calls. The increment of this index must be placed
just before the conditional expression that ends the single block loop. */
static tree
vect_create_index_for_array_ref (tree stmt, block_stmt_iterator *bsi)
vect_create_index_for_vector_ref (struct loop *loop, 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. */
gcc_assert (VARRAY_ACTIVE_SIZE (access_fns) == 1);
gcc_assert (vectorization_factor);
#endif
/* It is assumed that the base pointer used for vectorized access contains
the address of the first vector. Therefore the index used for vectorized
access must be initialized to zero and incremented by 1. */
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);
init = integer_zero_node;
step = integer_one_node;
gcc_assert (ok);
/* Assuming that bsi_insert is used with BSI_NEW_STMT */
create_iv (init, step, NULL_TREE, loop, bsi, false,
&indx_before_incr, &indx_after_incr);
/* FORNOW: Handling only constant 'init'. */
gcc_assert (TREE_CODE (init) == INTEGER_CST);
return indx_before_incr;
}
vf = build_int_cst (unsigned_type_node, vectorization_factor);
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);
}
/* Function vect_create_addr_base_for_vector_ref.
/* 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);
Create an expression that computes the address of the first memory location
that will be accessed for a data reference.
/* Calculate the 'step' of the new index. FORNOW: always 1. */
step = size_one_node;
Input:
STMT: The statement containing the data reference.
NEW_STMT_LIST: Must be initialized to NULL_TREE or a
statement list.
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, ")");
Output:
1. Return an SSA_NAME whose value is the address of the memory location of the
first vector of the data reference.
2. If new_stmt_list is not NULL_TREE after return then the caller must insert
these statement(s) which define the returned SSA_NAME.
FORNOW: We are only handling array accesses with step 1. */
static tree
vect_create_addr_base_for_vector_ref (tree stmt,
tree *new_stmt_list)
{
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 data_ref_base = unshare_expr (STMT_VINFO_VECT_DR_BASE (stmt_info));
tree base_name = unshare_expr (DR_BASE_NAME (dr));
tree ref = DR_REF (dr);
tree data_ref_base_type = TREE_TYPE (data_ref_base);
tree scalar_type = TREE_TYPE (ref);
tree scalar_ptr_type = build_pointer_type (scalar_type);
tree access_fn;
tree init_val, step, init_oval;
bool ok;
bool is_ptr_ref, is_array_ref, is_addr_expr;
tree array_base;
tree vec_stmt;
tree new_temp;
tree array_ref;
tree addr_base, addr_expr;
tree dest, new_stmt;
/* Only the access function of the last index is relevant (i_n in
a[i_1][i_2]...[i_n]), the others correspond to loop invariants. */
access_fn = DR_ACCESS_FN (dr, 0);
ok = vect_is_simple_iv_evolution (loop->num, access_fn, &init_oval, &step, true);
if (!ok)
init_oval = integer_zero_node;
is_ptr_ref = TREE_CODE (data_ref_base_type) == POINTER_TYPE
&& TREE_CODE (data_ref_base) == SSA_NAME;
is_array_ref = TREE_CODE (data_ref_base_type) == ARRAY_TYPE
&& (TREE_CODE (data_ref_base) == VAR_DECL
|| TREE_CODE (data_ref_base) == COMPONENT_REF
|| TREE_CODE (data_ref_base) == ARRAY_REF);
is_addr_expr = TREE_CODE (data_ref_base) == ADDR_EXPR
|| TREE_CODE (data_ref_base) == PLUS_EXPR
|| TREE_CODE (data_ref_base) == MINUS_EXPR;
gcc_assert (is_ptr_ref || is_array_ref || is_addr_expr);
/** Create: &(base[init_val])
if data_ref_base is an ARRAY_TYPE:
base = data_ref_base
if data_ref_base is the SSA_NAME of a POINTER_TYPE:
base = *((scalar_array *) data_ref_base)
**/
if (is_array_ref)
array_base = data_ref_base;
else /* is_ptr_ref or is_addr_expr */
{
/* array_ptr = (scalar_array_ptr_type *) data_ref_base; */
tree scalar_array_type = build_array_type (scalar_type, 0);
tree scalar_array_ptr_type = build_pointer_type (scalar_array_type);
tree array_ptr = create_tmp_var (scalar_array_ptr_type, "array_ptr");
add_referenced_tmp_var (array_ptr);
dest = create_tmp_var (TREE_TYPE (data_ref_base), "dataref");
add_referenced_tmp_var (dest);
data_ref_base = force_gimple_operand (data_ref_base, &new_stmt, false, dest);
append_to_statement_list_force (new_stmt, new_stmt_list);
vec_stmt = fold_convert (scalar_array_ptr_type, data_ref_base);
vec_stmt = build2 (MODIFY_EXPR, void_type_node, array_ptr, vec_stmt);
new_temp = make_ssa_name (array_ptr, vec_stmt);
TREE_OPERAND (vec_stmt, 0) = new_temp;
append_to_statement_list_force (vec_stmt, new_stmt_list);
/* (*array_ptr) */
array_base = build_fold_indirect_ref (new_temp);
}
create_iv (init, step, NULL_TREE, loop, bsi, false,
&indx_before_incr, &indx_after_incr);
dest = create_tmp_var (TREE_TYPE (init_oval), "newinit");
add_referenced_tmp_var (dest);
init_val = force_gimple_operand (init_oval, &new_stmt, false, dest);
append_to_statement_list_force (new_stmt, new_stmt_list);
return indx_before_incr;
array_ref = build4 (ARRAY_REF, scalar_type, array_base, init_val,
NULL_TREE, NULL_TREE);
addr_base = build_fold_addr_expr (array_ref);
/* addr_expr = addr_base */
addr_expr = vect_get_new_vect_var (scalar_ptr_type, vect_pointer_var,
get_name (base_name));
add_referenced_tmp_var (addr_expr);
vec_stmt = build2 (MODIFY_EXPR, void_type_node, addr_expr, addr_base);
new_temp = make_ssa_name (addr_expr, vec_stmt);
TREE_OPERAND (vec_stmt, 0) = new_temp;
append_to_statement_list_force (vec_stmt, new_stmt_list);
return new_temp;
}
......@@ -602,6 +821,7 @@ 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;
tree vectype;
if (nbytes == 0)
return NULL_TREE;
......@@ -610,7 +830,10 @@ get_vectype_for_scalar_type (tree scalar_type)
is expected. */
nunits = UNITS_PER_SIMD_WORD / nbytes;
return build_vector_type (scalar_type, nunits);
vectype = build_vector_type (scalar_type, nunits);
if (TYPE_MODE (vectype) == BLKmode)
return NULL_TREE;
return vectype;
}
......@@ -656,36 +879,39 @@ vect_align_data_ref (tree stmt)
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;
tree base_name, data_ref_base, data_ref_base_type;
tree array_type;
stmt_vec_info stmt_info = vinfo_for_stmt (stmt);
struct data_reference *dr = STMT_VINFO_DATA_REF (stmt_info);
struct loop *loop = STMT_VINFO_LOOP (stmt_info);
tree vectype = STMT_VINFO_VECTYPE (stmt_info);
tree vect_ptr_type;
tree vect_ptr;
tree addr_ref;
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;
tree use;
ssa_op_iter iter;
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;
tree new_temp;
tree vec_stmt;
tree new_stmt_list = NULL_TREE;
tree idx;
tree new_base;
tree data_ref;
edge pe;
basic_block new_bb;
/* FORNOW: make sure the data reference is aligned. */
vect_align_data_ref (stmt);
addr_ref = DR_BASE_NAME (dr);
base_name = unshare_expr (DR_BASE_NAME (dr));
data_ref_base = STMT_VINFO_VECT_DR_BASE (stmt_info);
data_ref_base_type = TREE_TYPE (data_ref_base);
array_type = build_array_type (vectype, 0);
TYPE_ALIGN (array_type) = TYPE_ALIGN (TREE_TYPE (addr_ref));
TYPE_ALIGN (array_type) = TYPE_ALIGN (data_ref_base_type);
vect_ptr_type = build_pointer_type (array_type);
scalar_ptr_type = build_pointer_type (TREE_TYPE (addr_ref));
if (vect_debug_details (NULL))
{
......@@ -693,70 +919,76 @@ vect_create_data_ref (tree stmt, block_stmt_iterator *bsi)
print_generic_expr (dump_file, vectype, TDF_SLIM);
}
/*** create: vectype_array *p; ***/
/* Create: vectype *p; */
vect_ptr = vect_get_new_vect_var (vect_ptr_type, vect_pointer_var,
get_name (addr_ref));
get_name (base_name));
add_referenced_tmp_var (vect_ptr);
gcc_assert (TREE_CODE (addr_ref) == VAR_DECL
|| TREE_CODE (addr_ref) == COMPONENT_REF
|| TREE_CODE (addr_ref) == SSA_NAME);
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)
if (TREE_CODE (data_ref_base) == VAR_DECL)
fprintf (dump_file, "vectorizing a one dimensional array ref: ");
else if (TREE_CODE (data_ref_base) == ARRAY_REF)
fprintf (dump_file, "vectorizing a multidimensional array ref: ");
else if (TREE_CODE (data_ref_base) == COMPONENT_REF)
fprintf (dump_file, "vectorizing a record based array ref: ");
else if (TREE_CODE (data_ref_base) == 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);
else if (TREE_CODE (data_ref_base) == ADDR_EXPR
|| TREE_CODE (data_ref_base) == PLUS_EXPR
|| TREE_CODE (data_ref_base) == MINUS_EXPR)
fprintf (dump_file, "vectorizing an address expr: ");
print_generic_expr (dump_file, base_name, 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);
gcc_assert (tag);
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) */
FOR_EACH_SSA_TREE_OPERAND (use, stmt, iter,
(SSA_OP_VIRTUAL_DEFS | SSA_OP_VUSE))
(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; ***/
/* Create: (&(base[init_val]) */
new_temp = vect_create_addr_base_for_vector_ref (stmt, &new_stmt_list);
/* 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);
pe = loop_preheader_edge (loop);
new_bb = bsi_insert_on_edge_immediate (pe, new_stmt_list);
gcc_assert (!new_bb);
/* vect_ptr = (vectype_array *)&a; */
/* p = (vectype_array *) addr_base */
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);
new_bb = bsi_insert_on_edge_immediate (pe, vec_stmt);
gcc_assert (!new_bb);
/*** create data ref: '(*p)[idx]' ***/
idx = vect_create_index_for_array_ref (stmt, bsi);
idx = vect_create_index_for_vector_ref (loop, bsi);
new_base = build_fold_indirect_ref (new_temp);
data_ref = build4 (ARRAY_REF, vectype, new_base, idx, NULL_TREE, NULL_TREE);
......@@ -809,6 +1041,7 @@ vect_init_vector (tree stmt, tree vector_var)
tree vec_oprnd;
edge pe;
tree new_temp;
basic_block new_bb;
new_var = vect_get_new_vect_var (vectype, vect_simple_var, "cst_");
add_referenced_tmp_var (new_var);
......@@ -818,7 +1051,8 @@ vect_init_vector (tree stmt, tree vector_var)
TREE_OPERAND (init_stmt, 0) = new_temp;
pe = loop_preheader_edge (loop);
bsi_insert_on_edge (pe, init_stmt);
new_bb = bsi_insert_on_edge_immediate (pe, init_stmt);
gcc_assert (!new_bb);
if (vect_debug_details (NULL))
{
......@@ -1935,9 +2169,9 @@ vect_analyze_scalar_cycles (loop_vec_info loop_vinfo)
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)));
access_fn = /* instantiate_parameters
(loop,*/
analyze_scalar_evolution (loop, PHI_RESULT (phi));
if (!access_fn)
{
......@@ -2105,32 +2339,151 @@ vect_get_first_index (tree ref, tree *array_first_index)
}
/* Function vect_compute_array_base_alignment.
A utility function of vect_compute_array_ref_alignment.
Compute the misalignment of ARRAY in bits.
Input:
ARRAY - an array_ref (possibly multidimensional) of type ARRAY_TYPE.
VECTYPE - we are interested in the misalignment modulu the size of vectype.
if NULL: don't compute misalignment, just return the base of ARRAY.
PREV_DIMENSIONS - initialized to one.
MISALIGNMENT - the computed misalignment in bits.
Output:
If VECTYPE is not NULL:
Return NULL_TREE if the misalignment cannot be computed. Otherwise, return
the base of the array, and put the computed misalignment in MISALIGNMENT.
If VECTYPE is NULL:
Return the base of the array.
For a[idx_N]...[idx_2][idx_1][idx_0], the address of
a[idx_N]...[idx_2][idx_1] is
{&a + idx_1 * dim_0 + idx_2 * dim_0 * dim_1 + ...
... + idx_N * dim_0 * ... * dim_N-1}.
(The misalignment of &a is not checked here).
Note, that every term contains dim_0, therefore, if dim_0 is a
multiple of NUNITS, the whole sum is a multiple of NUNITS.
Otherwise, if idx_1 is constant, and dim_1 is a multiple of
NUINTS, we can say that the misalignment of the sum is equal to
the misalignment of {idx_1 * dim_0}. If idx_1 is not constant,
we can't determine this array misalignment, and we return
false.
We proceed recursively in this manner, accumulating total misalignment
and the multiplication of previous dimensions for correct misalignment
calculation. */
static tree
vect_compute_array_base_alignment (tree array,
tree vectype,
tree *prev_dimensions,
tree *misalignment)
{
tree index;
tree domain;
tree dimension_size;
tree mis;
tree bits_per_vectype;
tree bits_per_vectype_unit;
/* The 'stop condition' of the recursion. */
if (TREE_CODE (array) != ARRAY_REF)
return array;
if (!vectype)
/* Just get the base decl. */
return vect_compute_array_base_alignment
(TREE_OPERAND (array, 0), NULL, NULL, NULL);
if (!host_integerp (*misalignment, 1) || TREE_OVERFLOW (*misalignment) ||
!host_integerp (*prev_dimensions, 1) || TREE_OVERFLOW (*prev_dimensions))
return NULL_TREE;
domain = TYPE_DOMAIN (TREE_TYPE (array));
dimension_size =
int_const_binop (PLUS_EXPR,
int_const_binop (MINUS_EXPR, TYPE_MAX_VALUE (domain),
TYPE_MIN_VALUE (domain), 1),
size_one_node, 1);
/* Check if the dimension size is a multiple of NUNITS, the remaining sum
is a multiple of NUNITS:
dimension_size % GET_MODE_NUNITS (TYPE_MODE (vectype)) == 0 ?
*/
mis = int_const_binop (TRUNC_MOD_EXPR, dimension_size,
build_int_cst (NULL_TREE, GET_MODE_NUNITS (TYPE_MODE (vectype))), 1);
if (integer_zerop (mis))
/* This array is aligned. Continue just in order to get the base decl. */
return vect_compute_array_base_alignment
(TREE_OPERAND (array, 0), NULL, NULL, NULL);
index = TREE_OPERAND (array, 1);
if (!host_integerp (index, 1))
/* The current index is not constant. */
return NULL_TREE;
index = int_const_binop (MINUS_EXPR, index, TYPE_MIN_VALUE (domain), 0);
bits_per_vectype = fold_convert (unsigned_type_node,
build_int_cst (NULL_TREE, BITS_PER_UNIT *
GET_MODE_SIZE (TYPE_MODE (vectype))));
bits_per_vectype_unit = fold_convert (unsigned_type_node,
build_int_cst (NULL_TREE, BITS_PER_UNIT *
GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (vectype)))));
/* Add {idx_i * dim_i-1 * ... * dim_0 } to the misalignment computed
earlier:
*misalignment =
(*misalignment + index_val * dimension_size * *prev_dimensions)
% vectype_nunits;
*/
mis = int_const_binop (MULT_EXPR, index, dimension_size, 1);
mis = int_const_binop (MULT_EXPR, mis, *prev_dimensions, 1);
mis = int_const_binop (MULT_EXPR, mis, bits_per_vectype_unit, 1);
mis = int_const_binop (PLUS_EXPR, *misalignment, mis, 1);
*misalignment = int_const_binop (TRUNC_MOD_EXPR, mis, bits_per_vectype, 1);
*prev_dimensions = int_const_binop (MULT_EXPR,
*prev_dimensions, dimension_size, 1);
return vect_compute_array_base_alignment (TREE_OPERAND (array, 0), vectype,
prev_dimensions,
misalignment);
}
/* Function vect_compute_data_ref_alignment
Compute the misalignment of the data reference DR.
Output:
1. If during the misalignment computation it is found that the data reference
cannot be vectorized then false is returned.
2. DR_MISALIGNMENT (DR) is defined.
FOR NOW: No analysis is actually performed. Misalignment is calculated
only for trivial cases. TODO. */
static void
static bool
vect_compute_data_ref_alignment (struct data_reference *dr,
loop_vec_info loop_vinfo ATTRIBUTE_UNUSED)
loop_vec_info loop_vinfo)
{
tree stmt = DR_STMT (dr);
stmt_vec_info stmt_info = vinfo_for_stmt (stmt);
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);
tree nunits;
tree alignment;
tree base, bit_offset, alignment;
tree unit_bits = fold_convert (unsigned_type_node,
build_int_cst (NULL_TREE, BITS_PER_UNIT));
tree dr_base;
bool base_aligned_p;
if (vect_debug_details (NULL))
fprintf (dump_file, "vect_compute_data_ref_alignment:");
......@@ -2146,74 +2499,151 @@ vect_compute_data_ref_alignment (struct data_reference *dr,
{
fprintf (dump_file, "no vectype for stmt: ");
print_generic_expr (dump_file, stmt, TDF_SLIM);
fprintf (dump_file, "scalar_type: ");
fprintf (dump_file, " scalar_type: ");
print_generic_expr (dump_file, scalar_type, TDF_DETAILS);
}
return;
/* It is not possible to vectorize this data reference. */
return false;
}
gcc_assert (TREE_CODE (ref) == ARRAY_REF || TREE_CODE (ref) == INDIRECT_REF);
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;
}
if (TREE_CODE (ref) == ARRAY_REF)
dr_base = ref;
else
dr_base = STMT_VINFO_VECT_DR_BASE (stmt_info);
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))
base = vect_get_base_and_bit_offset (dr, dr_base, vectype,
loop_vinfo, &bit_offset, &base_aligned_p);
if (!base)
{
if (vect_debug_details (NULL))
{
fprintf (dump_file, "bit offset alignment: ");
print_generic_expr (dump_file, bit_offset, TDF_SLIM);
fprintf (dump_file, "Unknown alignment for access: ");
print_generic_expr (dump_file,
STMT_VINFO_VECT_DR_BASE (stmt_info), TDF_SLIM);
}
return;
return true;
}
if (!base_decl ||
(DECL_ALIGN (base_decl) < TYPE_ALIGN (vectype)
&& !vect_can_force_dr_alignment_p (base_decl, TYPE_ALIGN (vectype))))
if (!base_aligned_p)
{
if (!vect_can_force_dr_alignment_p (base, 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);
print_generic_expr (dump_file, ref, TDF_SLIM);
}
return;
return true;
}
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);
DECL_ALIGN (base) = TYPE_ALIGN (vectype);
DECL_USER_ALIGN (base) = TYPE_ALIGN (vectype);
}
/* At this point we assume that the base is aligned, and the offset from it
(including index, if relevant) has been computed and is in BIT_OFFSET. */
gcc_assert (base_aligned_p
|| (TREE_CODE (base) == VAR_DECL
&& DECL_ALIGN (base) >= TYPE_ALIGN (vectype)));
/* Convert into bytes. */
offset = int_const_binop (TRUNC_DIV_EXPR, bit_offset, unit_bits, 1);
/* Check that there is no remainder in bits. */
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 false;
}
/* Alignment required, in bytes: */
alignment = fold_convert (unsigned_type_node,
build_int_cst (NULL_TREE, TYPE_ALIGN (vectype)/BITS_PER_UNIT));
/* Modulo alignment. */
offset = int_const_binop (TRUNC_MOD_EXPR, offset, alignment, 0);
if (!host_integerp (offset, 1) || TREE_OVERFLOW (offset))
{
if (vect_debug_details (NULL))
fprintf (dump_file, "unexpected misalign value");
return false;
}
/* 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. */
DR_MISALIGNMENT (dr) = tree_low_cst (offset, 1);
if (vect_debug_details (NULL))
fprintf (dump_file, "misalign = %d", DR_MISALIGNMENT (dr));
return true;
}
/* Function vect_compute_array_ref_alignment
Compute the alignment of an array-ref.
The alignment we compute here is relative to
TYPE_ALIGN(VECTYPE) boundary.
Output:
OFFSET - the alignment in bits
Return value - the base of the array-ref. E.g,
if the array-ref is a.b[k].c[i][j] the returned
base is a.b[k].c
*/
static tree
vect_compute_array_ref_alignment (struct data_reference *dr,
loop_vec_info loop_vinfo,
tree vectype,
tree *offset)
{
tree array_first_index = size_zero_node;
tree init;
tree ref = DR_REF (dr);
tree scalar_type = TREE_TYPE (ref);
tree oprnd0 = TREE_OPERAND (ref, 0);
tree dims = size_one_node;
tree misalign = size_zero_node;
tree next_ref, this_offset = size_zero_node;
tree nunits;
tree nbits;
if (TREE_CODE (TREE_TYPE (ref)) == ARRAY_TYPE)
/* The reference is an array without its last index. */
next_ref = vect_compute_array_base_alignment (ref, vectype, &dims, &misalign);
else
next_ref =
vect_compute_array_base_alignment (oprnd0, vectype, &dims, &misalign);
if (!vectype)
/* Alignment is not requested. Just return the base. */
return next_ref;
/* Compute alignment. */
if (!host_integerp (misalign, 1) || TREE_OVERFLOW (misalign) || !next_ref)
return NULL_TREE;
this_offset = misalign;
/* 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;
return NULL_TREE;
}
/* Check the index of the array_ref. */
init = initial_condition (access_fn);
init = initial_condition_in_loop_num (DR_ACCESS_FN (dr, 0),
LOOP_VINFO_LOOP (loop_vinfo)->num);
/* 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
......@@ -2223,58 +2653,33 @@ vect_compute_data_ref_alignment (struct data_reference *dr,
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 (!init || !host_integerp (init, 0))
{
if (vect_debug_details (NULL))
fprintf (dump_file, "init not simple INTEGER_CST.");
return;
fprintf (dump_file, "non constant init. ");
return NULL_TREE;
}
/* alignment required, in bytes: */
alignment = build_int_cst (unsigned_type_node,
TYPE_ALIGN (vectype)/BITS_PER_UNIT);
/* bytes per scalar element: */
nunits = build_int_cst (unsigned_type_node,
GET_MODE_SIZE (TYPE_MODE (scalar_type)));
/* 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, ">");
}
nunits = fold_convert (unsigned_type_node,
build_int_cst (NULL_TREE, GET_MODE_SIZE (TYPE_MODE (scalar_type))));
nbits = int_const_binop (MULT_EXPR, nunits,
build_int_cst (NULL_TREE, BITS_PER_UNIT), 1);
/* misalign = offset + (init-array_first_index)*nunits*bits_in_byte */
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);
misalign = int_const_binop (MULT_EXPR, misalign, nbits, 0);
misalign = int_const_binop (PLUS_EXPR, misalign, this_offset, 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))
/* TODO: allow negative misalign values. */
if (!host_integerp (misalign, 1) || TREE_OVERFLOW (misalign))
{
if (vect_debug_details (NULL))
fprintf (dump_file, "unexpected misalign value");
return;
return NULL_TREE;
}
DR_MISALIGNMENT (dr) = tree_low_cst (misalign,1);
if (vect_debug_details (NULL))
fprintf (dump_file, "misalign = %d",DR_MISALIGNMENT (dr));
*offset = misalign;
return next_ref;
}
......@@ -2486,23 +2891,40 @@ vect_analyze_data_ref_access (struct data_reference *dr)
varray_type access_fns = DR_ACCESS_FNS (dr);
tree access_fn;
tree init, step;
unsigned int dimensions, i;
/* FORNOW: handle only one dimensional arrays.
This restriction will be relaxed in the future. */
if (VARRAY_ACTIVE_SIZE (access_fns) != 1)
/* Check that in case of multidimensional array ref A[i1][i2]..[iN],
i1, i2, ..., iN-1 are loop invariant (to make sure that the memory
access is contiguous). */
dimensions = VARRAY_ACTIVE_SIZE (access_fns);
for (i = 1; i < dimensions; i++) /* Not including the last dimension. */
{
access_fn = DR_ACCESS_FN (dr, i);
if (evolution_part_in_loop_num (access_fn,
loop_containing_stmt (DR_STMT (dr))->num))
{
/* Evolution part is not NULL in this loop (it is neither constant nor
invariant). */
if (vect_debug_details (NULL))
fprintf (dump_file, "multi dimensional array reference.");
{
fprintf (dump_file,
"not vectorized: complicated multidimensional array access.");
print_generic_expr (dump_file, access_fn, TDF_SLIM);
}
return false;
}
access_fn = DR_ACCESS_FN (dr, 0);
}
if (!vect_is_simple_iv_evolution (loop_containing_stmt (DR_STMT (dr))->num,
access_fn = DR_ACCESS_FN (dr, 0); /* The last dimension access function. */
if (!evolution_function_is_constant_p (access_fn)
&& !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.");
fprintf (dump_file, "not vectorized: too complicated access function.");
print_generic_expr (dump_file, access_fn, TDF_SLIM);
}
return false;
......@@ -2519,7 +2941,7 @@ vect_analyze_data_ref_access (struct data_reference *dr)
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. */
FORNOW: handle only arrays and pointer accesses. */
static bool
vect_analyze_data_ref_accesses (loop_vec_info loop_vinfo)
......@@ -2604,12 +3026,13 @@ vect_analyze_pointer_ref_access (tree memref, tree stmt, bool is_read)
return NULL;
}
if (TREE_CODE (init) != SSA_NAME /* FORNOW */
|| !host_integerp (step,0))
STRIP_NOPS (init);
if (!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.");
"not vectorized: non constant step for pointer access.");
return NULL;
}
......@@ -2653,11 +3076,150 @@ vect_analyze_pointer_ref_access (tree memref, tree stmt, bool is_read)
}
/* Function vect_get_symbl_and_dr.
The function returns SYMBL - the relevant variable for
memory tag (for aliasing purposes).
Also data reference structure DR is created.
Input:
MEMREF - data reference in STMT
IS_READ - TRUE if STMT reads from MEMREF, FALSE if writes to MEMREF
Output:
DR - data_reference struct for MEMREF
return value - the relevant variable for memory tag (for aliasing purposes).
*/
static tree
vect_get_symbl_and_dr (tree memref, tree stmt, bool is_read,
loop_vec_info loop_vinfo, struct data_reference **dr)
{
tree symbl, oprnd0, oprnd1;
stmt_vec_info stmt_info = vinfo_for_stmt (stmt);
tree offset;
tree array_base, base;
struct data_reference *new_dr;
bool base_aligned_p;
*dr = NULL;
switch (TREE_CODE (memref))
{
case INDIRECT_REF:
new_dr = vect_analyze_pointer_ref_access (memref, stmt, is_read);
if (! new_dr)
return NULL_TREE;
*dr = new_dr;
symbl = DR_BASE_NAME (new_dr);
STMT_VINFO_VECT_DR_BASE (stmt_info) = symbl;
switch (TREE_CODE (symbl))
{
case PLUS_EXPR:
case MINUS_EXPR:
oprnd0 = TREE_OPERAND (symbl, 0);
oprnd1 = TREE_OPERAND (symbl, 1);
STRIP_NOPS(oprnd1);
/* Only {address_base + offset} expressions are supported,
where address_base can be POINTER_TYPE or ARRRAY_TYPE and
offset can be anything but POINTER_TYPE or ARRAY_TYPE.
TODO: swap operands if {offset + address_base}. */
if ((TREE_CODE (TREE_TYPE (oprnd1)) == POINTER_TYPE
&& TREE_CODE (oprnd1) != INTEGER_CST)
|| TREE_CODE (TREE_TYPE (oprnd1)) == ARRAY_TYPE)
return NULL_TREE;
if (TREE_CODE (TREE_TYPE (oprnd0)) == POINTER_TYPE)
symbl = oprnd0;
else
symbl = vect_get_symbl_and_dr (oprnd0, stmt, is_read,
loop_vinfo, &new_dr);
case SSA_NAME:
case ADDR_EXPR:
/* symbl remains unchanged. */
break;
default:
if (vect_debug_details (NULL))
{
fprintf (dump_file, "unhandled data ref: ");
print_generic_expr (dump_file, memref, TDF_SLIM);
fprintf (dump_file, " (symbl ");
print_generic_expr (dump_file, symbl, TDF_SLIM);
fprintf (dump_file, ") in stmt ");
print_generic_expr (dump_file, stmt, TDF_SLIM);
}
return NULL_TREE;
}
break;
case ARRAY_REF:
offset = size_zero_node;
array_base = TREE_OPERAND (memref, 0);
/* Store the array base in the stmt info.
For one dimensional array ref a[i], the base is a,
for multidimensional a[i1][i2]..[iN], the base is
a[i1][i2]..[iN-1]. */
array_base = TREE_OPERAND (memref, 0);
STMT_VINFO_VECT_DR_BASE (stmt_info) = array_base;
new_dr = analyze_array (stmt, memref, is_read);
*dr = new_dr;
/* Find the relevant symbol for aliasing purposes. */
base = DR_BASE_NAME (new_dr);
switch (TREE_CODE (base))
{
case VAR_DECL:
symbl = base;
break;
case INDIRECT_REF:
symbl = TREE_OPERAND (base, 0);
break;
case COMPONENT_REF:
/* 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_and_bit_offset (new_dr, base, NULL_TREE,
loop_vinfo, &offset, &base_aligned_p);
if (symbl)
break;
/* fall through */
default:
if (vect_debug_details (NULL))
{
fprintf (dump_file, "unhandled struct/class field access ");
print_generic_expr (dump_file, stmt, TDF_SLIM);
}
return NULL_TREE;
}
break;
default:
if (vect_debug_details (NULL))
{
fprintf (dump_file, "unhandled data ref: ");
print_generic_expr (dump_file, memref, TDF_SLIM);
fprintf (dump_file, " in stmt ");
print_generic_expr (dump_file, stmt, TDF_SLIM);
}
return NULL_TREE;
}
return symbl;
}
/* Function vect_analyze_data_refs.
Find all the data references in the loop.
FORNOW: Handle aligned INDIRECT_REFs and one dimensional ARRAY_REFs
FORNOW: Handle aligned INDIRECT_REFs and ARRAY_REFs
which base is really an array (not a pointer) and which alignment
can be forced. This restriction will be relaxed. */
......@@ -2670,6 +3232,8 @@ vect_analyze_data_refs (loop_vec_info loop_vinfo)
block_stmt_iterator si;
int j;
struct data_reference *dr;
tree tag;
tree address_base;
if (vect_debug_details (NULL))
fprintf (dump_file, "\n<<vect_analyze_data_refs>>\n");
......@@ -2688,7 +3252,6 @@ vect_analyze_data_refs (loop_vec_info loop_vinfo)
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
......@@ -2734,80 +3297,28 @@ vect_analyze_data_refs (loop_vec_info 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)
/* Analyze MEMREF. If it is of a supported form, build data_reference
struct for it (DR) and find the relevant symbol for aliasing
purposes. */
symbl = vect_get_symbl_and_dr (memref, stmt, is_read, loop_vinfo, &dr);
if (!symbl)
{
if (vect_debug_stats (loop) || vect_debug_details (loop))
{
fprintf (dump_file,
"not vectorized: multi-dimensional array.");
fprintf (dump_file, "not vectorized: unhandled data ref: ");
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))
/* Find and record the memtag assigned to this data-ref. */
switch (TREE_CODE (symbl))
{
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)
STMT_VINFO_MEMTAG (stmt_info) = 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;
case SSA_NAME:
symbl = SSA_NAME_VAR (symbl);
tag = get_var_ann (symbl)->type_mem_tag;
if (!tag)
......@@ -2823,9 +3334,33 @@ vect_analyze_data_refs (loop_vec_info loop_vinfo)
return false;
}
STMT_VINFO_MEMTAG (stmt_info) = tag;
}
else
break;
case ADDR_EXPR:
address_base = TREE_OPERAND (symbl, 0);
switch (TREE_CODE (address_base))
{
case ARRAY_REF:
dr = analyze_array (stmt, TREE_OPERAND (symbl, 0), DR_IS_READ(dr));
STMT_VINFO_MEMTAG (stmt_info) = DR_BASE_NAME (dr);
break;
case VAR_DECL:
STMT_VINFO_MEMTAG (stmt_info) = address_base;
break;
default:
if (vect_debug_stats (loop) || vect_debug_details (loop))
{
fprintf (dump_file, "not vectorized: unhandled address expression: ");
print_generic_expr (dump_file, stmt, TDF_SLIM);
}
return false;
}
break;
default:
if (vect_debug_stats (loop) || vect_debug_details (loop))
{
fprintf (dump_file, "not vectorized: unsupported data-ref: ");
......@@ -3235,7 +3770,7 @@ vect_analyze_loop (struct loop *loop)
/* 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
FORNOW: Handle only simple, array references, which
alignment can be forced, and aligned pointer-references. */
ok = vect_analyze_data_refs (loop_vinfo);
......@@ -3247,7 +3782,6 @@ vect_analyze_loop (struct loop *loop)
return NULL;
}
/* Data-flow analysis to detect stmts that do not need to be vectorized. */
ok = vect_mark_stmts_to_be_vectorized (loop_vinfo);
......@@ -3261,7 +3795,6 @@ vect_analyze_loop (struct loop *loop)
return NULL;
}
/* Check that all cross-iteration scalar data-flow cycles are OK.
Cross-iteration cycles caused by virtual phis are analyzed separately. */
......@@ -3274,7 +3807,6 @@ vect_analyze_loop (struct loop *loop)
return NULL;
}
/* Analyze data dependences between the data-refs in the loop.
FORNOW: fail at the first data dependence that we encounter. */
......@@ -3287,7 +3819,6 @@ vect_analyze_loop (struct loop *loop)
return NULL;
}
/* Analyze the access patterns of the data-refs in the loop (consecutive,
complex, etc.). FORNOW: Only handle consecutive access pattern. */
......@@ -3300,7 +3831,6 @@ vect_analyze_loop (struct loop *loop)
return NULL;
}
/* Analyze the alignment of the data-refs in the loop.
FORNOW: Only aligned accesses are handled. */
......@@ -3313,7 +3843,6 @@ vect_analyze_loop (struct loop *loop)
return NULL;
}
/* Scan all the operations in the loop and make sure they are
vectorizable. */
......@@ -3400,14 +3929,15 @@ vectorize_loops (struct loops *loops)
for (i = 1; i < loops_num; i++)
{
struct loop *loop = loops->parray[i];
loop_vec_info loop_vinfo = loop->aux;
loop_vec_info loop_vinfo;
if (!loop)
continue;
loop_vinfo = loop->aux;
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)
{
......
......@@ -76,6 +76,15 @@ typedef struct _stmt_vec_info {
/* Aliasing information. */
tree memtag;
/* Data reference base. This field holds the entire invariant part of the
data-reference (with respect to the relevant loop), as opposed to the
field DR_BASE of the STMT_VINFO_DATA_REF struct, which holds only the
initial base; e.g:
REF BR_BASE VECT_DR_BASE
a[i] a a
a[i][j] a a[i] */
tree vect_dr_base;
} *stmt_vec_info;
/* Access Functions. */
......@@ -87,6 +96,7 @@ typedef struct _stmt_vec_info {
#define STMT_VINFO_VEC_STMT(S) (S)->vectorized_stmt
#define STMT_VINFO_DATA_REF(S) (S)->data_ref_info
#define STMT_VINFO_MEMTAG(S) (S)->memtag
#define STMT_VINFO_VECT_DR_BASE(S) (S)->vect_dr_base
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);
......@@ -123,6 +133,9 @@ unknown_alignment_for_access_p (struct data_reference *data_ref_info)
return (DR_MISALIGNMENT (data_ref_info) == -1);
}
/* Perform signed modulo, always returning a non-negative value. */
#define VECT_SMODULO(x,y) ((x) % (y) < 0 ? ((x) % (y) + (y)) : (x) % (y))
/*-----------------------------------------------------------------*/
/* Info on vectorized loops. */
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment