#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 "tree-fold-const.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"
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_dependences (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);
static void vect_transform_loop (loop_vec_info, struct loops *);
static void vect_transform_loop_bound (loop_vec_info, tree);
static bool vect_transform_stmt (tree, block_stmt_iterator *);
static tree vect_transform_load (tree, block_stmt_iterator *);
static tree vect_transform_store (tree, block_stmt_iterator *);
static tree vect_transform_op (tree, block_stmt_iterator *);
static tree vect_transform_assignment (tree, block_stmt_iterator *);
static tree vect_transform_select (tree, block_stmt_iterator *);
static tree vect_transform_compare (tree, block_stmt_iterator *);
static void vect_align_data_ref (tree, tree);
static void vect_enhance_data_refs_alignment (loop_vec_info);
static bool vect_is_supportable_op (tree);
static bool vect_is_supportable_operation (tree, tree, struct loop *);
static bool vect_is_supportable_store (tree);
static bool vect_is_supportable_load (tree);
static bool vect_is_supportable_assignment (tree);
static bool vect_is_supportable_compare (tree);
static bool vect_is_supportable_select (tree);
static bool vect_is_simple_use (tree , struct loop *);
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 *, 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_analyze_data_ref_dependence
(struct data_reference *, struct data_reference *);
static bool vect_get_array_first_index (tree, int *);
static bool vect_force_dr_alignment_p (struct data_reference *);
static bool vect_analyze_loop_with_symbolic_num_of_iters (tree *, struct loop *);
static tree vect_create_destination_var (tree, tree);
static tree vect_create_data_ref (tree, tree, block_stmt_iterator *, bool,
tree *);
static tree vect_create_index_for_array_ref (tree, block_stmt_iterator *,
int *);
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 tree vect_build_symbl_bound (tree n, int vf, struct loop * loop);
static basic_block vect_gen_if_guard (edge, tree, basic_block, edge);
static basic_block vect_tree_split_edge (edge);
static void vect_update_initial_conditions_of_duplicated_loop (loop_vec_info,
tree, basic_block, edge, edge);
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 void vect_loop_version (struct loops *, struct loop *, basic_block *);
static bool second_loop_vers_available;
static bool if_converted_loop;
#define DEFTREECODE(SYM, STRING, TYPE, NARGS) NARGS,
int tree_nargs[] = {
#include "tree.def"
};
#undef DEFTREECODE
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;
return res;
}
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);
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;
LOOP_VINFO_SYMB_NUM_OF_ITERS (res) = NULL;
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;
}
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);
}
static bool
vect_force_dr_alignment_p (struct data_reference *dr)
{
tree ref = DR_REF (dr);
tree array_base;
if (TREE_CODE (ref) != ARRAY_REF)
return false;
array_base = get_array_base (ref);
if (TREE_CODE (TREE_TYPE (array_base)) != ARRAY_TYPE
|| TREE_CODE (array_base) != VAR_DECL
|| DECL_EXTERNAL (array_base))
{
if (dump_file && (dump_flags & TDF_DETAILS))
{
fprintf (dump_file, "unhandled ptr-based array ref\n");
if (TREE_CODE (array_base) == VAR_DECL && DECL_EXTERNAL (array_base))
fprintf (dump_file,"\nextern decl.\n");
}
return false;
}
return true;
}
static tree
vect_get_new_vect_var (tree type, enum vect_var_kind var_kind, const char *name)
{
const char *prefix;
int prefix_len;
char *vect_var_name;
tree new_vect_var;
if (var_kind == vect_simple_var)
prefix = "vect_";
else
prefix = "vect_p";
prefix_len = strlen (prefix);
if (name)
{
vect_var_name = (char *) xmalloc (strlen (name) + prefix_len + 1);
sprintf (vect_var_name, "%s%s", prefix, name);
}
else
{
vect_var_name = (char *) xmalloc (prefix_len + 1);
sprintf (vect_var_name, "%s", prefix);
}
new_vect_var = create_tmp_var (type, vect_var_name);
free (vect_var_name);
return new_vect_var;
}
static tree
vect_create_index_for_array_ref (tree stmt, block_stmt_iterator *bsi,
int * init_val)
{
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);
varray_type access_fns = DR_ACCESS_FNS (dr);
tree access_fn;
tree scalar_indx;
int step_val;
tree init, step;
bool ok;
int array_first_index;
tree indx_before_incr, indx_after_incr;
if (TREE_CODE (expr) != ARRAY_REF)
abort ();
if (VARRAY_ACTIVE_SIZE (access_fns) != 1)
abort ();
access_fn = DR_ACCESS_FN (dr, 0);
if (!vect_is_simple_iv_evolution (loop_num (loop), access_fn, &init, &step,
true))
abort ();
if (TREE_CODE (init) != INTEGER_CST || TREE_CODE (step) != INTEGER_CST)
abort ();
if (TREE_INT_CST_HIGH (init) != 0 || TREE_INT_CST_HIGH (step) != 0)
abort ();
*init_val = TREE_INT_CST_LOW (init);
step_val = TREE_INT_CST_LOW (step);
scalar_indx = TREE_OPERAND (expr, 1);
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, "creating update chain:\n");
ok = vect_get_array_first_index (expr, &array_first_index);
if (!ok)
abort ();
init = integer_zero_node;
step = integer_one_node;
create_iv (init, step, NULL_TREE, loop, bsi, false,
&indx_before_incr, &indx_after_incr);
return indx_before_incr;
}
static tree
get_vectype_for_scalar_type (tree scalar_type)
{
enum machine_mode inner_mode;
enum machine_mode vec_mode;
int nbytes;
int nunits;
inner_mode = TYPE_MODE (scalar_type);
nbytes = GET_MODE_SIZE (inner_mode);
if (nbytes == 0)
return NULL_TREE;
nunits = UNITS_PER_SIMD_WORD / nbytes;
if (GET_MODE_CLASS (inner_mode) == MODE_FLOAT)
vec_mode = MIN_MODE_VECTOR_FLOAT;
else
vec_mode = MIN_MODE_VECTOR_INT;
if (dump_file && (dump_flags & TDF_DETAILS))
{
fprintf (dump_file, "\nget vectype for scalar type: ");
print_generic_expr (dump_file, scalar_type, TDF_SLIM);
fprintf (dump_file, "\n");
}
for (; vec_mode != VOIDmode ; vec_mode = GET_MODE_WIDER_MODE (vec_mode))
if (GET_MODE_NUNITS (vec_mode) == nunits
&& GET_MODE_INNER (vec_mode) == inner_mode
&& VECTOR_MODE_SUPPORTED_P (vec_mode))
return build_vector_type (scalar_type, nunits);
return NULL_TREE;
}
static void
vect_align_data_ref (tree ref, tree stmt)
{
stmt_vec_info stmt_info = vinfo_for_stmt (stmt);
tree vectype = STMT_VINFO_VECTYPE (stmt_info);
tree array_base = get_array_base (ref);
struct data_reference *dr = STMT_VINFO_DATA_REF (stmt_info);
if (!aligned_access_p (dr))
abort ();
if (vect_force_dr_alignment_p (dr))
{
if (DECL_ALIGN (array_base) < TYPE_ALIGN (vectype))
{
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file,
"\nforce alignment. before: scalar/vec type_align = %d/%d\n",
DECL_ALIGN (array_base), TYPE_ALIGN (vectype));
DECL_ALIGN (array_base) = TYPE_ALIGN (vectype);
}
}
}
static tree
vect_create_data_ref (tree ref, tree stmt, block_stmt_iterator *bsi,
bool use_max_misaligned_offset, tree * ptr)
{
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 ptr_type;
tree array_ptr;
tree array_base;
tree array_ref;
vdef_optype vdefs = STMT_VDEF_OPS (stmt);
vuse_optype vuses = STMT_VUSE_OPS (stmt);
int nvuses = 0, nvdefs = 0;
int i;
int init_val;
if (dump_file && (dump_flags & TDF_DETAILS))
{
fprintf (dump_file, "create array_ref of type:\n");
print_generic_expr (dump_file, vectype, TDF_SLIM);
}
array_base = get_array_base (ref);
ptr_type = build_pointer_type (vectype);
array_ptr = vect_get_new_vect_var (ptr_type, vect_pointer_var,
get_name (array_base));
add_referenced_tmp_var (array_ptr);
if (TREE_CODE (array_base) == VAR_DECL)
{
get_var_ann (array_ptr)->type_mem_tag = array_base;
bitmap_set_bit (vars_to_rename, var_ann (array_base)->uid);
}
else
{
abort ();
}
if (vuses)
nvuses = NUM_VUSES (vuses);
if (vdefs)
nvdefs = NUM_VDEFS (vdefs);
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 < nvdefs; i++)
{
tree def = VDEF_RESULT (vdefs, i);
if (TREE_CODE (def) == SSA_NAME)
bitmap_set_bit (vars_to_rename, var_ann (SSA_NAME_VAR (def))->uid);
}
idx = vect_create_index_for_array_ref (stmt, bsi, &init_val);
if (use_max_misaligned_offset)
{
struct loop *loop = STMT_VINFO_LOOP (stmt_info);
loop_vec_info loop_info = loop->aux;
int vectorization_factor = LOOP_VINFO_VECT_FACTOR (loop_info);
init_val += vectorization_factor - 1;
}
array_ref = build (ARRAY_REF, TREE_TYPE (array_base), array_base,
build_int_2 (init_val, 0));
vec_stmt = build (MODIFY_EXPR, void_type_node, array_ptr,
build1 (NOP_EXPR, ptr_type,
build1 (ADDR_EXPR,
build_pointer_type (TREE_TYPE (array_base)),
array_ref)));
TREE_ADDRESSABLE (array_base) = 1;
new_temp = make_ssa_name (array_ptr, vec_stmt);
TREE_OPERAND (vec_stmt, 0) = new_temp;
bsi_insert_before (bsi, vec_stmt, BSI_SAME_STMT);
*ptr = new_temp;
new_base = build1 (INDIRECT_REF, build_array_type (vectype, 0),
TREE_OPERAND (vec_stmt, 0));
data_ref = build (ARRAY_REF, vectype, new_base, idx);
if (dump_file && (dump_flags & TDF_DETAILS))
print_generic_expr (dump_file, data_ref, TDF_SLIM);
return data_ref;
}
static tree
vect_create_destination_var (tree scalar_dest, tree vectype)
{
tree vec_dest;
const char *new_name;
if (TREE_CODE (scalar_dest) != SSA_NAME)
abort ();
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);
TYPE_ALIAS_SET (TREE_TYPE (vec_dest)) =
TYPE_ALIAS_SET (TREE_TYPE (scalar_dest));
return vec_dest;
}
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);
block_stmt_iterator pre_header_bsi;
tree new_var;
tree init_stmt;
tree vectype = STMT_VINFO_VECTYPE (stmt_vinfo);
tree vec_oprnd;
new_var = vect_get_new_vect_var (vectype, vect_simple_var, "cst_");
add_referenced_tmp_var (new_var);
bitmap_set_bit (vars_to_rename, var_ann (new_var)->uid);
if (dump_file && (dump_flags & TDF_DETAILS))
{
print_generic_expr (dump_file, vector_var, TDF_SLIM);
fprintf (dump_file, "\n");
}
init_stmt = build (MODIFY_EXPR, vectype, new_var, vector_var);
if (dump_file && (dump_flags & TDF_DETAILS))
{
print_generic_expr (dump_file, init_stmt, TDF_SLIM);
fprintf (dump_file, "\n");
}
pre_header_bsi = bsi_last (loop->pre_header);
if (!bsi_end_p (pre_header_bsi)
&& is_ctrl_stmt (bsi_stmt (pre_header_bsi)))
bsi_insert_before (&pre_header_bsi, init_stmt, BSI_NEW_STMT);
else
bsi_insert_after (&pre_header_bsi, init_stmt, BSI_NEW_STMT);
vec_oprnd = TREE_OPERAND (init_stmt, 0);
if (dump_file && (dump_flags & TDF_DETAILS))
{
print_generic_expr (dump_file, vec_oprnd, TDF_SLIM);
fprintf (dump_file, "\n");
}
return vec_oprnd;
}
static tree
vect_get_vec_def_for_operand (tree op, tree stmt)
{
tree vec_oprnd;
if (!op)
abort ();
if (TREE_CODE (op) == SSA_NAME)
{
tree vec_stmt;
tree def_stmt;
stmt_vec_info def_stmt_info = NULL;
def_stmt = SSA_NAME_DEF_STMT (op);
def_stmt_info = vinfo_for_stmt (def_stmt);
if (dump_file && (dump_flags & TDF_DETAILS))
{
fprintf (dump_file, "vect_get_vec_def_for_operand: def_stmt:\n");
print_generic_expr (dump_file, def_stmt, TDF_SLIM);
}
if (!def_stmt_info)
{
tree vec_inv;
stmt_vec_info stmt_vinfo = vinfo_for_stmt (stmt);
tree vectype = STMT_VINFO_VECTYPE (stmt_vinfo);
int nunits = GET_MODE_NUNITS (TYPE_MODE (vectype));
basic_block bb = bb_for_stmt (def_stmt);
struct loop *loop = STMT_VINFO_LOOP (stmt_vinfo);
tree t = NULL_TREE;
tree def;
int i;
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, "\nCreate vector_inv.\n");
if (TREE_CODE (def_stmt) == PHI_NODE)
{
if (flow_bb_inside_loop_p (loop, bb))
{
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, "\nUnsupported reduction.\n");
abort ();
}
def = PHI_RESULT (def_stmt);
}
else if (TREE_CODE (def_stmt) == NOP_EXPR)
{
tree arg = TREE_OPERAND (def_stmt, 0);
if (TREE_CODE (arg) != INTEGER_CST && TREE_CODE (arg) != REAL_CST)
{
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, "\nUnsupported NOP_EXPR.\n");
abort ();
}
def = op;
}
else
def = TREE_OPERAND (def_stmt, 0);
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);
}
vec_stmt = STMT_VINFO_VEC_STMT (def_stmt_info);
if (!vec_stmt)
abort ();
vec_oprnd = TREE_OPERAND (vec_stmt, 0);
return vec_oprnd;
}
if (TREE_CODE (op) == INTEGER_CST
|| TREE_CODE (op) == REAL_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;
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, "\nCreate vector_cst.\n");
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);
}
return NULL_TREE;
}
static tree
vect_transform_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);
tree new_temp;
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, "transform assignment\n");
if (TREE_CODE (stmt) != MODIFY_EXPR)
abort ();
scalar_dest = TREE_OPERAND (stmt, 0);
if (TREE_CODE (scalar_dest) != SSA_NAME)
abort ();
vec_dest = vect_create_destination_var (scalar_dest, vectype);
op = TREE_OPERAND (stmt, 1);
vec_oprnd = vect_get_vec_def_for_operand (op, stmt);
if (! vec_oprnd)
abort ();
vec_stmt = build (MODIFY_EXPR, vectype, vec_dest, vec_oprnd);
new_temp = make_ssa_name (vec_dest, vec_stmt);
TREE_OPERAND (vec_stmt, 0) = new_temp;
if (dump_file && (dump_flags & TDF_DETAILS))
{
fprintf (dump_file, "add new stmt\n");
print_generic_stmt (dump_file, vec_stmt, TDF_SLIM);
}
bsi_insert_before (bsi, vec_stmt, BSI_SAME_STMT);
return vec_stmt;
}
static tree
vect_transform_compare (tree stmt, block_stmt_iterator *bsi)
{
tree vec_stmt;
tree vec_dest;
tree scalar_dest;
tree operand;
tree vec_oprnd;
tree operand1;
tree vec_oprnd1;
stmt_vec_info stmt_info = vinfo_for_stmt (stmt);
tree vectype = STMT_VINFO_VECTYPE (stmt_info);
tree new_temp;
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, "transform select\n");
if (TREE_CODE (stmt) != MODIFY_EXPR)
abort ();
scalar_dest = TREE_OPERAND (stmt, 0);
if (TREE_CODE (scalar_dest) != SSA_NAME)
abort ();
vec_dest = vect_create_destination_var (scalar_dest, vectype);
if (TREE_CODE_CLASS (TREE_CODE (TREE_OPERAND (stmt, 1))) != '<')
abort ();
operand = TREE_OPERAND (TREE_OPERAND (stmt, 1), 0);
vec_oprnd = vect_get_vec_def_for_operand (operand, stmt);
if (! vec_oprnd)
abort ();
operand1 = TREE_OPERAND (TREE_OPERAND (stmt, 1), 1);
vec_oprnd1 = vect_get_vec_def_for_operand (operand1, stmt);
if (! vec_oprnd)
abort ();
vec_stmt = targetm.vect.vector_compare_stmt (vectype, vec_dest,
vec_oprnd, vec_oprnd1,
TREE_CODE (TREE_OPERAND (stmt, 1)));
new_temp = make_ssa_name (vec_dest, vec_stmt);
TREE_OPERAND (vec_stmt, 0) = new_temp;
if (dump_file && (dump_flags & TDF_DETAILS))
{
fprintf (dump_file, "add new stmt\n");
print_generic_stmt (dump_file, vec_stmt, TDF_SLIM);
}
bsi_insert_before (bsi, vec_stmt, BSI_SAME_STMT);
return vec_stmt;
}
static tree
vect_transform_select (tree stmt, block_stmt_iterator *bsi)
{
tree vec_stmt;
tree vec_dest;
tree scalar_dest;
tree op;
tree vec_oprnd;
tree op2;
tree vec_oprnd2;
tree cond;
tree vec_cond;
stmt_vec_info stmt_info = vinfo_for_stmt (stmt);
tree vectype = STMT_VINFO_VECTYPE (stmt_info);
tree new_temp;
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, "transform select\n");
if (TREE_CODE (stmt) != MODIFY_EXPR)
abort ();
scalar_dest = TREE_OPERAND (stmt, 0);
if (TREE_CODE (scalar_dest) != SSA_NAME)
abort ();
vec_dest = vect_create_destination_var (scalar_dest, vectype);
if (TREE_CODE (TREE_OPERAND (stmt, 1)) != COND_EXPR)
abort ();
cond = TREE_OPERAND (TREE_OPERAND (stmt, 1), 0);
if (TREE_CODE (cond) != SSA_NAME)
abort ();
vec_cond = vect_get_vec_def_for_operand (cond, stmt);
if (! vec_cond)
abort ();
op = TREE_OPERAND (TREE_OPERAND (stmt, 1), 1);
vec_oprnd = vect_get_vec_def_for_operand (op, stmt);
if (! vec_oprnd)
abort ();
op2 = TREE_OPERAND (TREE_OPERAND (stmt, 1), 2);
if (TREE_CODE (op2) == NOP_EXPR)
op2 = integer_zero_node;
vec_oprnd2 = vect_get_vec_def_for_operand (op2, stmt);
if (! vec_oprnd2)
abort ();
vec_stmt = targetm.vect.vector_select_stmt (vectype, vec_dest,
vec_cond, vec_oprnd2, vec_oprnd);
new_temp = make_ssa_name (vec_dest, vec_stmt);
TREE_OPERAND (vec_stmt, 0) = new_temp;
if (dump_file && (dump_flags & TDF_DETAILS))
{
fprintf (dump_file, "add new stmt\n");
print_generic_stmt (dump_file, vec_stmt, TDF_SLIM);
}
bsi_insert_before (bsi, vec_stmt, BSI_SAME_STMT);
return vec_stmt;
}
static tree
vect_transform_op (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);
enum tree_code code;
tree new_temp;
int op_type;
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, "transform op\n");
if (TREE_CODE (stmt) != MODIFY_EXPR)
abort ();
operation = TREE_OPERAND (stmt, 1);
scalar_dest = TREE_OPERAND (stmt, 0);
if (TREE_CODE (scalar_dest) != SSA_NAME)
abort ();
vec_dest = vect_create_destination_var (scalar_dest, vectype);
op_type = tree_nargs[TREE_CODE (operation)];
if (op_type != unary_op && op_type != binary_op)
abort ();
op0 = TREE_OPERAND (operation, 0);
if (op_type == binary_op)
op1 = TREE_OPERAND (operation, 1);
vec_oprnd0 = vect_get_vec_def_for_operand (op0, stmt);
if (! vec_oprnd0)
abort ();
if(op_type == binary_op)
{
vec_oprnd1 = vect_get_vec_def_for_operand (op1, stmt);
if (! vec_oprnd1)
abort ();
}
code = TREE_CODE (operation);
if (op_type == binary_op)
vec_stmt = build (MODIFY_EXPR, vectype, vec_dest,
build (code, vectype, vec_oprnd0, vec_oprnd1));
else
vec_stmt = build (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;
if (dump_file && (dump_flags & TDF_DETAILS))
{
fprintf (dump_file, "add new stmt\n");
print_generic_stmt (dump_file, vec_stmt, TDF_SLIM);
}
bsi_insert_before (bsi, vec_stmt, BSI_SAME_STMT);
return vec_stmt;
}
static tree
vect_transform_store (tree stmt, block_stmt_iterator *bsi)
{
tree scalar_dest;
tree vec_stmt;
tree data_ref;
tree op;
tree vec_oprnd1;
stmt_vec_info stmt_info = vinfo_for_stmt (stmt);
tree vectype = STMT_VINFO_VECTYPE (stmt_info);
tree t;
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, "transform store\n");
if (TREE_CODE (stmt) != MODIFY_EXPR)
abort ();
scalar_dest = TREE_OPERAND (stmt, 0);
if (TREE_CODE (scalar_dest) != ARRAY_REF)
abort ();
vect_align_data_ref (scalar_dest, stmt);
data_ref = vect_create_data_ref (scalar_dest, stmt, bsi, false, &t);
if (!data_ref)
abort ();
op = TREE_OPERAND (stmt, 1);
vec_oprnd1 = vect_get_vec_def_for_operand (op, stmt);
if (! vec_oprnd1)
abort ();
vec_stmt = build (MODIFY_EXPR, vectype, data_ref, vec_oprnd1);
if (dump_file && (dump_flags & TDF_DETAILS))
{
fprintf (dump_file, "add new stmt\n");
print_generic_stmt (dump_file, vec_stmt, TDF_SLIM);
}
bsi_insert_before (bsi, vec_stmt, BSI_SAME_STMT);
if (stmt != bsi_stmt (*bsi))
{
if (dump_file && (dump_flags & TDF_DETAILS))
{
fprintf (dump_file, "update chain:\n");
print_generic_stmt (dump_file, bsi_stmt (*bsi), TDF_SLIM);
}
bsi_next (bsi);
}
if (stmt != bsi_stmt (*bsi))
abort ();
return vec_stmt;
}
static void
vect_finish_stmt_generation (tree stmt, tree vec_stmt, block_stmt_iterator *bsi)
{
if (dump_file && (dump_flags & TDF_DETAILS))
{
fprintf (dump_file, "add new stmt\n");
print_generic_stmt (dump_file, vec_stmt, TDF_SLIM);
}
bsi_insert_before (bsi, vec_stmt, BSI_SAME_STMT);
if (stmt != bsi_stmt (*bsi))
{
if (dump_file && (dump_flags & TDF_DETAILS))
{
fprintf (dump_file, "update chain:\n");
print_generic_stmt (dump_file, bsi_stmt (*bsi), TDF_SLIM);
}
bsi_next (bsi);
}
if (stmt != bsi_stmt (*bsi))
abort ();
}
static tree
vect_transform_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;
tree ptr;
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, "transform load\n");
if (TREE_CODE (stmt) != MODIFY_EXPR)
abort ();
scalar_dest = TREE_OPERAND (stmt, 0);
if (TREE_CODE (scalar_dest) != SSA_NAME)
abort ();
vec_dest = vect_create_destination_var (scalar_dest, vectype);
if (!vec_dest)
abort ();
op = TREE_OPERAND (stmt, 1);
if (TREE_CODE (op) != ARRAY_REF)
abort ();
if (!aligned_access_p (STMT_VINFO_DATA_REF (stmt_info))
&& (!targetm.vect.support_misaligned_loads
|| !(*targetm.vect.support_misaligned_loads) ()))
abort ();
if (aligned_access_p (STMT_VINFO_DATA_REF (stmt_info)))
vect_align_data_ref (op, stmt);
data_ref = vect_create_data_ref (op, stmt, bsi, false, &ptr);
if (!data_ref)
abort ();
vec_stmt = build (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);
if (!aligned_access_p (STMT_VINFO_DATA_REF (stmt_info))
&& targetm.vect.permute_misaligned_loads
&& (*targetm.vect.permute_misaligned_loads) ())
{
tree lsq, mask, tmp, result, arg;
tree lsq_data_ref;
tree vec_ld_lsq_stmt;
tree vec_lvsl_stmt;
tree vec_perm_stmt;
tree V16QI_type_node;
tree lsq_ptr;
lsq_data_ref = vect_create_data_ref (op, stmt, bsi, true, &lsq_ptr);
vec_dest = vect_create_destination_var (scalar_dest, vectype);
if (!vec_dest)
abort ();
vec_ld_lsq_stmt = build (MODIFY_EXPR, vectype, vec_dest, lsq_data_ref);
lsq = make_ssa_name (vec_dest, vec_ld_lsq_stmt);
TREE_OPERAND (vec_ld_lsq_stmt, 0) = lsq;
vect_finish_stmt_generation (stmt, vec_ld_lsq_stmt, bsi);
V16QI_type_node = build_vector_type (intQI_type_node, 16);
vec_dest = vect_create_destination_var (scalar_dest, V16QI_type_node);
if (!vec_dest)
abort ();
arg = tree_cons (NULL, ptr, NULL);
arg = tree_cons (NULL, integer_zero_node, arg);
if (!targetm.vect.build_builtin_lvsl)
abort ();
tmp = (*targetm.vect.build_builtin_lvsl) ();
if (tmp == NULL_TREE)
abort ();
vec_lvsl_stmt = build_function_call_expr (tmp, arg);
vec_lvsl_stmt = build (MODIFY_EXPR, vectype, vec_dest, vec_lvsl_stmt);
mask = make_ssa_name (vec_dest, vec_lvsl_stmt);
TREE_OPERAND (vec_lvsl_stmt, 0) = mask;
vect_finish_stmt_generation (stmt, vec_lvsl_stmt, bsi);
vec_dest = vect_create_destination_var (scalar_dest, vectype);
if (!vec_dest)
abort ();
arg = tree_cons (NULL, mask, NULL);
arg = tree_cons (NULL, lsq, arg);
arg = tree_cons (NULL, new_temp, arg);
if (!targetm.vect.build_builtin_vperm)
abort ();
tmp = (*targetm.vect.build_builtin_vperm) (TYPE_MODE (vectype));
if (tmp == NULL_TREE)
abort ();
vec_perm_stmt = build_function_call_expr (tmp, arg);
vec_perm_stmt = build (MODIFY_EXPR, vectype, vec_dest, vec_perm_stmt);
result = make_ssa_name (vec_dest, vec_perm_stmt);
TREE_OPERAND (vec_perm_stmt, 0) = result;
vect_finish_stmt_generation (stmt, vec_perm_stmt, bsi);
vec_stmt = vec_perm_stmt;
}
return vec_stmt;
}
static bool
vect_transform_stmt (tree stmt, block_stmt_iterator *bsi)
{
bool is_store = false;
tree vec_stmt = NULL;
stmt_vec_info stmt_info = vinfo_for_stmt (stmt);
switch (STMT_VINFO_TYPE (stmt_info))
{
case op_vec_info_type:
vec_stmt = vect_transform_op (stmt, bsi);
break;
case assignment_vec_info_type:
vec_stmt = vect_transform_assignment (stmt, bsi);
break;
case load_vec_info_type:
vec_stmt = vect_transform_load (stmt, bsi);
break;
case store_vec_info_type:
vec_stmt = vect_transform_store (stmt, bsi);
is_store = true;
break;
case select_vec_info_type:
vec_stmt = vect_transform_select (stmt, bsi);
break;
case compare_vec_info_type:
vec_stmt = vect_transform_compare (stmt, bsi);
break;
default:
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, "stmt not supported\n");
abort ();
}
STMT_VINFO_VEC_STMT (stmt_info) = vec_stmt;
return is_store;
}
static void
vect_generate_tmps_on_preheader (loop_vec_info loop_vinfo, tree *ni_name_p,
tree *ratio_mult_vf_name_p, tree *ratio_p)
{
edge pe;
basic_block new_bb;
tree stmt, var, ni, ni_name;
tree ratio;
tree ratio_mult_vf_name, ratio_mult_vf;
struct loop *loop = LOOP_VINFO_LOOP (loop_vinfo);
int vf, i = -1;
ni = LOOP_VINFO_SYMB_NUM_OF_ITERS(loop_vinfo);
var = create_tmp_var (TREE_TYPE (ni), "niters");
add_referenced_tmp_var (var);
ni_name = force_gimple_operand (ni, &stmt, false, var);
pe = loop_preheader_edge (loop);
new_bb = bsi_insert_on_edge_immediate (pe, stmt);
if (new_bb)
add_bb_to_loop (new_bb, new_bb->pred->src->loop_father);
vf = LOOP_VINFO_VECT_FACTOR (loop_vinfo);
ratio = vect_build_symbl_bound (ni_name, vf, loop);
while (vf)
{
vf = vf >> 1;
i++;
}
ratio_mult_vf = create_tmp_var (TREE_TYPE (ni), "ratio_mult_vf");
add_referenced_tmp_var (ratio_mult_vf);
ratio_mult_vf_name = make_ssa_name (ratio_mult_vf, NULL_TREE);
stmt = build (MODIFY_EXPR, void_type_node, ratio_mult_vf_name,
build (LSHIFT_EXPR, TREE_TYPE (ratio),
ratio, build_int_2(i,0)));
SSA_NAME_DEF_STMT (ratio_mult_vf_name) = stmt;
pe = loop_preheader_edge (loop);
new_bb = bsi_insert_on_edge_immediate (pe, stmt);
if (new_bb)
add_bb_to_loop (new_bb, new_bb->pred->src->loop_father);
*ni_name_p = ni_name;
*ratio_mult_vf_name_p = ratio_mult_vf_name;
*ratio_p = ratio;
return;
}
static basic_block
vect_gen_if_guard (edge ee, tree cond, basic_block exit_bb, edge e)
{
tree cond_expr;
tree then_clause,else_clause;
basic_block new_bb;
edge true_edge, false_edge;
tree phi, phi1;
basic_block header_of_loop;
int num_elem1, num_elem2;
edge e0;
block_stmt_iterator interm_bb_last_bsi;
new_bb = vect_tree_split_edge (ee);
add_bb_to_loop (new_bb, exit_bb->loop_father);
if(!new_bb)
{
if (dump_file && (dump_flags & TDF_DETAILS))
{
fprintf (dump_file, "\nFailed to generate new_bb.\n");
}
abort ();
}
header_of_loop = new_bb->succ->dest;
then_clause = build1 (GOTO_EXPR, void_type_node, tree_block_label (exit_bb));
else_clause = build1 (GOTO_EXPR, void_type_node,
tree_block_label (header_of_loop));
cond_expr = build (COND_EXPR, void_type_node, cond, then_clause, else_clause);
interm_bb_last_bsi = bsi_last (new_bb);
bsi_insert_after (&interm_bb_last_bsi, cond_expr, BSI_NEW_STMT);
e0 = new_bb->succ;
remove_edge (e0);
true_edge = make_edge (new_bb, exit_bb, EDGE_TRUE_VALUE);
set_immediate_dominator (CDI_DOMINATORS, exit_bb, new_bb);
false_edge = make_edge (new_bb, header_of_loop, EDGE_FALSE_VALUE);
set_immediate_dominator (CDI_DOMINATORS, header_of_loop, new_bb);
for (phi = phi_nodes (header_of_loop); phi; phi = TREE_CHAIN (phi))
{
int i;
num_elem1 = PHI_NUM_ARGS (phi);
for (i = 0; i < num_elem1; i++)
if (PHI_ARG_EDGE (phi, i) == e0)
{
PHI_ARG_EDGE (phi, i) = false_edge;
break;
}
}
for (phi = phi_nodes (exit_bb); phi; phi = TREE_CHAIN (phi))
{
int i;
num_elem1 = PHI_NUM_ARGS (phi);
for (i = 0; i < num_elem1; i++)
{
if (PHI_ARG_EDGE (phi, i) == e)
{
tree def = PHI_ARG_DEF (phi, i);
for (phi1 = phi_nodes (header_of_loop); phi1; phi1 = TREE_CHAIN (phi1))
{
int k;
num_elem2 = PHI_NUM_ARGS (phi1);
for (k = 0; k < num_elem2; k++)
{
if (PHI_ARG_DEF (phi1, k) == def)
{
int j;
for (j = 0; j < num_elem2; j++)
{
if (PHI_ARG_EDGE (phi1, j) == false_edge)
{
tree def1 = PHI_ARG_DEF (phi1, j);
add_phi_arg (&phi, def1, true_edge);
break;
}
}
break;
}
}
}
}
}
}
return new_bb;
}
static tree
vect_build_symbl_bound (tree n, int vf, struct loop * loop)
{
tree var, stmt, var_name;
edge pe;
basic_block new_bb;
int i = -1;
var = create_tmp_var (TREE_TYPE (n), "bnd");
add_referenced_tmp_var (var);
var_name = make_ssa_name (var, NULL_TREE);
while (vf)
{
vf = vf >> 1;
i++;
}
stmt = build (MODIFY_EXPR, void_type_node, var_name,
build (RSHIFT_EXPR, TREE_TYPE (n),
n, build_int_2(i,0)));
SSA_NAME_DEF_STMT (var_name) = stmt;
pe = loop_preheader_edge (loop);
new_bb = bsi_insert_on_edge_immediate (pe, stmt);
if (new_bb)
add_bb_to_loop (new_bb, new_bb->pred->src->loop_father);
else
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, "\nNew bb on preheader edge was not generated.\n");
return var_name;
}
static void
vect_update_initial_conditions_of_duplicated_loop (loop_vec_info loop_vinfo,
tree niters,
basic_block new_loop_header,
edge new_loop_latch,
edge new_loop_exit)
{
struct loop *loop = LOOP_VINFO_LOOP (loop_vinfo);
edge pe;
edge latch = loop_latch_edge (loop);
tree phi;
block_stmt_iterator interm_bb_last_bsi;
basic_block intermediate_bb = loop->exit_edges[0]->dest;
edge inter_bb_true_edge;
basic_block exit_bb;
pe = find_edge (loop->exit_edges[0]->dest, new_loop_header);
inter_bb_true_edge = find_edge (intermediate_bb, new_loop_exit->dest);
exit_bb = new_loop_exit->dest;
for (phi = phi_nodes (loop->header); phi; phi = TREE_CHAIN (phi))
{
tree access_fn = NULL;
tree evolution_part;
tree init_expr;
tree step_expr;
tree var, stmt, ni, ni_name;
int i, j, k, m, num_elem1, num_elem2, num_elem3;
tree phi1, phi2;
if (!is_gimple_reg (SSA_NAME_VAR (PHI_RESULT (phi))))
{
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, "virtual phi. skip.\n");
continue;
}
access_fn = instantiate_parameters
(loop,
analyze_scalar_evolution (loop, PHI_RESULT (phi)));
evolution_part = evolution_part_in_loop_num (access_fn, loop_num(loop));
step_expr = evolution_part;
init_expr = initial_condition (access_fn);
ni = build (PLUS_EXPR, TREE_TYPE (init_expr),
build (MULT_EXPR, TREE_TYPE (niters),
niters, step_expr), init_expr);
var = create_tmp_var (TREE_TYPE (init_expr), "tmp");
add_referenced_tmp_var (var);
ni_name = force_gimple_operand (ni, &stmt, false, var);
interm_bb_last_bsi = bsi_last (intermediate_bb);
bsi_insert_before (&interm_bb_last_bsi, stmt, BSI_NEW_STMT);
num_elem1 = PHI_NUM_ARGS (phi);
for (i = 0; i < num_elem1; i++)
if (PHI_ARG_EDGE (phi, i) == latch)
{
tree def;
def = PHI_ARG_DEF (phi, i);
for (phi1 = phi_nodes (new_loop_header); phi1; phi1 = TREE_CHAIN (phi1))
{
num_elem2 = PHI_NUM_ARGS (phi1);
for (j = 0; j < num_elem2; j++)
if (PHI_ARG_DEF (phi1, i) == def)
{
for (k = 0; k < num_elem2; k++)
if (PHI_ARG_EDGE (phi1, k) == new_loop_latch)
{
tree def1 = PHI_ARG_DEF (phi1, k);
for (phi2 = phi_nodes (exit_bb); phi2; phi2 = TREE_CHAIN (phi2))
{
num_elem3 = PHI_NUM_ARGS (phi2);
for (m = 0; m < num_elem3; m++)
{
if (PHI_ARG_DEF (phi2, m) == def1 &&
PHI_ARG_EDGE (phi2, m) == new_loop_exit)
{
add_phi_arg (&phi2, ni_name, inter_bb_true_edge);
break;
}
}
}
}
PHI_ARG_DEF (phi1, j) = ni_name;
PHI_ARG_EDGE (phi1, j) = pe;
break;
}
}
break;
}
}
}
static basic_block
vect_tree_split_edge (edge edge_in)
{
basic_block new_bb, dest, src;
edge new_edge;
tree phi;
int i, num_elem;
if (edge_in->flags & EDGE_ABNORMAL)
abort ();
src = edge_in->src;
dest = edge_in->dest;
new_bb = create_empty_bb (src);
new_edge = make_edge (new_bb, dest, EDGE_FALLTHRU);
for (phi = phi_nodes (dest); phi; phi = TREE_CHAIN (phi))
{
num_elem = PHI_NUM_ARGS (phi);
for (i = 0; i < num_elem; i++)
if (PHI_ARG_EDGE (phi, i) == edge_in)
{
PHI_ARG_EDGE (phi, i) = new_edge;
break;
}
}
if (!redirect_edge_and_branch (edge_in, new_bb))
abort ();
set_immediate_dominator (CDI_DOMINATORS, new_bb, src);
set_immediate_dominator (CDI_DOMINATORS, dest, new_bb);
new_bb->loop_father = src->loop_father->outer;
if (PENDING_STMT (edge_in))
abort ();
return new_bb;
}
static void
vect_transform_loop_bound (loop_vec_info loop_vinfo, tree niters)
{
struct loop *loop = LOOP_VINFO_LOOP (loop_vinfo);
edge exit_edge = loop_exit_edge (loop, 0);
block_stmt_iterator loop_exit_bsi = bsi_last (exit_edge->src);
tree indx_before_incr, indx_after_incr;
tree orig_cond_expr;
int old_N = 0, vf;
tree cond_stmt;
tree new_loop_bound;
bool symbl_niters;
if (LOOP_VINFO_NITERS_KNOWN_P (loop_vinfo))
symbl_niters = false;
else if (LOOP_VINFO_SYMB_NUM_OF_ITERS (loop_vinfo) != NULL)
symbl_niters = true;
else
abort ();
if(!symbl_niters)
old_N = LOOP_VINFO_NITERS (loop_vinfo);
vf = LOOP_VINFO_VECT_FACTOR (loop_vinfo);
if (!symbl_niters && old_N % vf)
abort ();
orig_cond_expr = LOOP_VINFO_EXIT_COND (loop_vinfo);
if (!orig_cond_expr)
abort ();
if (orig_cond_expr != bsi_stmt (loop_exit_bsi))
abort ();
create_iv (integer_zero_node, integer_one_node, NULL_TREE, loop,
&loop_exit_bsi, false, &indx_before_incr, &indx_after_incr);
bsi_next (&loop_exit_bsi);
if (bsi_stmt (loop_exit_bsi) != orig_cond_expr)
abort ();
if(!symbl_niters)
new_loop_bound = build_int_2 (old_N/vf, 0);
else
new_loop_bound = niters;
cond_stmt =
build (COND_EXPR, TREE_TYPE (orig_cond_expr),
build (LT_EXPR, boolean_type_node, indx_after_incr, new_loop_bound),
TREE_OPERAND (orig_cond_expr, 1), TREE_OPERAND (orig_cond_expr, 2));
bsi_insert_before (&loop_exit_bsi, cond_stmt, BSI_SAME_STMT);
bsi_remove (&loop_exit_bsi);
if (dump_file && (dump_flags & TDF_DETAILS))
print_generic_expr (dump_file, cond_stmt, TDF_SLIM);
}
static void
vect_transform_loop (loop_vec_info loop_vinfo, struct loops *loops)
{
struct loop *loop = LOOP_VINFO_LOOP (loop_vinfo);
basic_block *bbs = LOOP_VINFO_BBS (loop_vinfo);
int nbbs = loop->num_nodes;
int vectorization_factor = LOOP_VINFO_VECT_FACTOR (loop_vinfo);
block_stmt_iterator si;
int i;
tree ratio = NULL;
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, "\n<<vec_transform_loop>>\n");
if ( LOOP_VINFO_NITERS (loop_vinfo) == -1 &&
LOOP_VINFO_SYMB_NUM_OF_ITERS (loop_vinfo) != NULL )
{
basic_block inter_bb, exit_bb, prolog_bb;
tree ni_name, ratio_mult_vf_name;
basic_block new_loop_header;
tree cond;
int vf;
edge e, exit_ep, phead_epilog, ee;
exit_bb = loop->exit_edges[0]->dest;
tree_duplicate_loop_to_exit (loop, loops);
new_loop_header = loop->exit_edges[0]->dest;
vect_generate_tmps_on_preheader (loop_vinfo, &ni_name,
&ratio_mult_vf_name, &ratio);
loop->pre_header = loop_preheader_edge (loop)->src;
loop->pre_header_edges[0] = loop_preheader_edge (loop);
cond = build (EQ_EXPR, boolean_type_node, ratio_mult_vf_name, ni_name);
exit_ep = find_edge (new_loop_header, exit_bb);
inter_bb = vect_gen_if_guard (loop->exit_edges[0], cond, exit_bb, exit_ep);
loop->exit_edges[0] = inter_bb->pred;
vf = LOOP_VINFO_VECT_FACTOR (loop_vinfo);
cond = build (LT_EXPR, boolean_type_node, ni_name, build_int_2 (vf,0));
phead_epilog = find_edge (inter_bb, new_loop_header);
prolog_bb = vect_gen_if_guard (loop->pre_header_edges[0], cond,
new_loop_header, phead_epilog);
loop->pre_header = prolog_bb;
loop->pre_header_edges[0] = find_edge (prolog_bb, loop->header);
for (ee = prolog_bb->succ; ee; ee = ee->succ_next)
if(ee->dest != loop->header)
break;
if (!ee)
abort ();
for (e = new_loop_header->pred; e; e = e->pred_next)
if(e != ee && e != phead_epilog)
break;
if (!e)
abort ();
vect_update_initial_conditions_of_duplicated_loop (loop_vinfo, ratio_mult_vf_name,
new_loop_header, e, exit_ep);
}
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;
tree vectype;
bool is_store;
if (dump_file && (dump_flags & TDF_DETAILS))
{
fprintf (dump_file, "\n-----\nvectorizing statement:\n");
print_generic_stmt (dump_file, stmt, TDF_SLIM);
}
stmt_info = vinfo_for_stmt (stmt);
if (!stmt_info)
abort ();
if (!STMT_VINFO_RELEVANT_P (stmt_info))
{
bsi_next (&si);
continue;
}
vectype = STMT_VINFO_VECTYPE (stmt_info);
if (GET_MODE_NUNITS (TYPE_MODE (vectype)) != vectorization_factor)
abort ();
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, "transform statement.\n");
is_store = vect_transform_stmt (stmt, &si);
if (is_store)
{
stmt_ann_t ann = stmt_ann (stmt);
free (stmt_info);
set_stmt_info (ann, NULL);
bsi_remove (&si);
continue;
}
bsi_next (&si);
}
}
vect_transform_loop_bound (loop_vinfo, ratio);
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, "\n<<Success! loop vectorized.>>\n");
}
static bool
vect_is_simple_use (tree operand, struct loop *loop)
{
tree def_stmt;
basic_block bb;
if (!operand)
return false;
if (TREE_CODE (operand) == SSA_NAME)
{
def_stmt = SSA_NAME_DEF_STMT (operand);
if (def_stmt == NULL_TREE)
return false;
if (TREE_CODE (def_stmt) == NOP_EXPR)
{
tree arg = TREE_OPERAND (def_stmt, 0);
if (TREE_CODE (arg) == INTEGER_CST || TREE_CODE (arg) == REAL_CST)
return true;
return false;
}
bb = bb_for_stmt (def_stmt);
if (TREE_CODE (def_stmt) == PHI_NODE && flow_bb_inside_loop_p (loop, bb))
{
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file,
"use defined in loop phi - some form of reduction.\n");
return false;
}
return true;
}
if (TREE_CODE (operand) == INTEGER_CST
|| TREE_CODE (operand) == REAL_CST)
{
return true;
}
return false;
}
static bool
vect_is_supportable_op (tree stmt)
{
stmt_vec_info stmt_info = vinfo_for_stmt (stmt);
tree operation;
tree vectype = STMT_VINFO_VECTYPE (stmt_info);
struct loop *loop = STMT_VINFO_LOOP (stmt_info);
if (TREE_CODE (stmt) != MODIFY_EXPR)
return false;
if (TREE_CODE (TREE_OPERAND (stmt, 0)) != SSA_NAME)
return false;
operation = TREE_OPERAND (stmt, 1);
if (vect_is_supportable_operation (operation, vectype, loop))
{
STMT_VINFO_TYPE (stmt_info) = op_vec_info_type;
return true;
}
else
return false;
}
static bool
vect_is_supportable_operation (tree operation, tree vectype, struct loop *loop)
{
enum tree_code code;
tree operand;
enum machine_mode vec_mode;
optab optab;
int i,op_type;
code = TREE_CODE (operation);
switch (code)
{
case PLUS_EXPR:
optab = add_optab;
break;
case MULT_EXPR:
optab = smul_optab;
break;
case MINUS_EXPR:
optab = sub_optab;
break;
case BIT_AND_EXPR:
optab = and_optab;
break;
case BIT_XOR_EXPR:
optab = xor_optab;
break;
case BIT_IOR_EXPR:
optab = ior_optab;
break;
case BIT_NOT_EXPR:
optab = one_cmpl_optab;
break;
default:
return false;
}
op_type = tree_nargs[code];
if (op_type != unary_op && op_type != binary_op)
return false;
for (i = 0; i < op_type; i++)
{
operand = TREE_OPERAND (operation, i);
if (!vect_is_simple_use (operand, loop))
{
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, "use not simple.\n");
return false;
}
}
if (!optab)
return false;
vec_mode = TYPE_MODE (vectype);
if (optab->handlers[(int) vec_mode].insn_code == CODE_FOR_nothing)
{
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, "operation not supported by target\n");
return false;
}
return true;
}
static bool
vect_is_supportable_store (tree stmt)
{
stmt_vec_info stmt_info = vinfo_for_stmt (stmt);
tree scalar_dest;
tree op;
struct loop *loop = STMT_VINFO_LOOP (stmt_info);
if (TREE_CODE (stmt) != MODIFY_EXPR)
return false;
scalar_dest = TREE_OPERAND (stmt, 0);
if (TREE_CODE (scalar_dest) != ARRAY_REF)
return false;
op = TREE_OPERAND (stmt, 1);
if (!vect_is_simple_use (op, loop))
{
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, "use not simple.\n");
return false;
}
if (!STMT_VINFO_DATA_REF (stmt_info))
return false;
STMT_VINFO_TYPE (stmt_info) = store_vec_info_type;
return true;
}
static bool
vect_is_supportable_load (tree stmt)
{
stmt_vec_info stmt_info = vinfo_for_stmt (stmt);
tree scalar_dest;
tree op;
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)
return false;
if (!STMT_VINFO_DATA_REF (stmt_info))
return false;
STMT_VINFO_TYPE (stmt_info) = load_vec_info_type;
return true;
}
static bool
vect_is_supportable_assignment (tree stmt)
{
stmt_vec_info stmt_info = vinfo_for_stmt (stmt);
tree scalar_dest;
tree op;
struct loop *loop = STMT_VINFO_LOOP (stmt_info);
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))
{
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, "use not simple.\n");
return false;
}
STMT_VINFO_TYPE (stmt_info) = assignment_vec_info_type;
return true;
}
static bool
vect_is_supportable_compare (tree stmt)
{
stmt_vec_info stmt_info = vinfo_for_stmt (stmt);
tree op, op0, op1;
tree vectype = STMT_VINFO_VECTYPE (stmt_info);
struct loop *loop = STMT_VINFO_LOOP (stmt_info);
if (TREE_CODE (stmt) != MODIFY_EXPR)
return false;
op = TREE_OPERAND (stmt, 1);
if (TREE_CODE_CLASS (TREE_CODE (op)) != '<')
return false;
op0 = TREE_OPERAND (op, 0);
op1 = TREE_OPERAND (op, 1);
if (!vect_is_simple_use (op0, loop))
{
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, "use not simple.\n");
return false;
}
if (!vect_is_simple_use (op1, loop))
{
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, "use not simple.\n");
return false;
}
if (!targetm.vect.support_vector_compare_for_p (vectype, TREE_CODE (op)))
{
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, "target does not support vector compare.\n");
return false;
}
STMT_VINFO_TYPE (stmt_info) = compare_vec_info_type;
return true;
}
static bool
vect_is_supportable_select (tree stmt)
{
stmt_vec_info stmt_info = vinfo_for_stmt (stmt);
tree op, op0, op1, op2;
tree vectype = STMT_VINFO_VECTYPE (stmt_info);
struct loop *loop = STMT_VINFO_LOOP (stmt_info);
if (TREE_CODE (stmt) != MODIFY_EXPR)
return false;
op = TREE_OPERAND (stmt, 1);
if (TREE_CODE (op) != COND_EXPR)
return false;
op0 = TREE_OPERAND (op, 0);
op1 = TREE_OPERAND (op, 1);
op2 = TREE_OPERAND (op, 2);
if (!vect_is_simple_use (op0, loop))
{
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, "use not simple.\n");
return false;
}
if (TREE_CODE (op1) == SSA_NAME)
{
if (!vect_is_simple_use (op0, loop))
{
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, "use not simple.\n");
return false;
}
}
else if ( TREE_CODE (op1) != INTEGER_CST
&& TREE_CODE (op1) != REAL_CST
&& !vect_is_supportable_operation (op1, vectype, loop))
{
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, "use not simple.\n");
return false;
}
if (op2
&& TREE_CODE (op2) != NOP_EXPR
&& TREE_CODE (op2) != INTEGER_CST
&& TREE_CODE (op2) != REAL_CST
&& !vect_is_supportable_operation (op2, vectype, loop))
{
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, "use not simple.\n");
return false;
}
STMT_VINFO_TYPE (stmt_info) = select_vec_info_type;
return true;
}
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 (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, "\n<<vect_analyze_operations>>\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;
dataflow_t df;
int j, num_uses;
vdef_optype vdefs;
if (dump_file && (dump_flags & TDF_DETAILS))
{
fprintf (dump_file, "\n-------\nexamining statement:\n");
print_generic_stmt (dump_file, stmt, TDF_SLIM);
}
if (!stmt_info)
abort ();
if (!STMT_VINFO_RELEVANT_P (stmt_info))
{
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, "irrelevant.\n");
continue;
}
vdefs = STMT_VDEF_OPS (stmt);
if (!vdefs)
{
df = get_immediate_uses (stmt);
num_uses = num_immediate_uses (df);
for (j = 0; j < num_uses; j++)
{
tree use = immediate_use (df, j);
basic_block bb = bb_for_stmt (use);
if (!flow_bb_inside_loop_p (loop, bb))
{
if (dump_file && (dump_flags & TDF_DETAILS))
{
fprintf (dump_file, "def used out of loop:\n");
print_generic_stmt (dump_file, use, TDF_SLIM);
}
return false;
}
}
}
if (VECTOR_MODE_P (TYPE_MODE (TREE_TYPE (stmt))))
{
if (dump_file && (dump_flags & TDF_DETAILS))
{
fprintf (dump_file, "vector stmt in loop!\n");
print_generic_stmt (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
scalar_type = TREE_TYPE (stmt);
vectype = get_vectype_for_scalar_type (scalar_type);
if (!vectype)
{
if (dump_file && (dump_flags & TDF_DETAILS))
{
fprintf (dump_file, "no vectype for stmt.\n");
print_generic_stmt (dump_file, stmt, TDF_SLIM);
}
return false;
}
STMT_VINFO_VECTYPE (stmt_info) = vectype;
ok = (vect_is_supportable_op (stmt)
|| vect_is_supportable_assignment (stmt)
|| vect_is_supportable_load (stmt)
|| vect_is_supportable_store (stmt)
|| vect_is_supportable_select (stmt)
|| vect_is_supportable_compare (stmt));
if (!ok)
{
if (dump_file && (dump_flags & TDF_DETAILS))
{
fprintf (dump_file, "stmt not supported.\n");
print_generic_stmt (dump_file, stmt, TDF_SLIM);
}
return false;
}
nunits = GET_MODE_NUNITS (TYPE_MODE (vectype));
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, "nunits = %d\n", nunits);
if (vectorization_factor)
{
if (nunits != vectorization_factor)
{
if (dump_file && (dump_flags & TDF_DETAILS))
{
fprintf (dump_file, "mixed types unsupported.\n");
print_generic_stmt (dump_file, stmt, TDF_SLIM);
}
return false;
}
}
else
vectorization_factor = nunits;
}
}
LOOP_VINFO_VECT_FACTOR (loop_vinfo) = vectorization_factor;
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, "vectorization_factor = %d, niters = %d\n",
vectorization_factor, LOOP_VINFO_NITERS (loop_vinfo));
if (vectorization_factor == 0
|| (!LOOP_VINFO_NITERS_KNOWN_P (loop_vinfo) &&
!LOOP_VINFO_SYMB_NUM_OF_ITERS(loop_vinfo)))
{
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file,
"Complicate loop bound.\n");
return false;
}
if (LOOP_VINFO_NITERS_KNOWN_P (loop_vinfo) &&
LOOP_VINFO_NITERS (loop_vinfo) % vectorization_factor != 0)
{
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file,
"loop bound does not divided by %d.\n",
vectorization_factor);
return false;
}
return true;
}
static bool
exist_non_indexing_operands_for_use_p (tree use, tree stmt)
{
tree operand;
stmt_vec_info stmt_info = vinfo_for_stmt (stmt);
if (dump_file && (dump_flags & TDF_DETAILS))
{
fprintf (dump_file, "exist_non_indexing_operands_for_use_p?:\n");
print_generic_stmt (dump_file, stmt, TDF_SLIM);
}
if (!STMT_VINFO_DATA_REF (stmt_info))
return true;
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;
}
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);
if (evolution_part == NULL_TREE)
return false;
if (TREE_CODE (evolution_part) == POLYNOMIAL_CHREC
|| TREE_CODE (evolution_part) == EXPONENTIAL_CHREC)
return false;
step_expr = evolution_part;
init_expr = initial_condition (access_fn);
if (dump_file && (dump_flags & TDF_DETAILS))
{
fprintf (dump_file, "\nstep: ");
print_generic_expr (dump_file, step_expr, TDF_SLIM);
fprintf (dump_file, "\ninit: ");
print_generic_expr (dump_file, init_expr, TDF_SLIM);
fprintf (dump_file, "\n");
}
*init = init_expr;
*step = step_expr;
if (TREE_CODE (step_expr) != INTEGER_CST)
{
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, "\nstep unknown.\n");
return false;
}
if (strict)
if (!integer_onep (step_expr))
{
if (dump_file && (dump_flags & TDF_DETAILS))
print_generic_expr (dump_file, step_expr, TDF_SLIM);
return false;
}
return true;
}
static bool
vect_analyze_scalar_cycles (loop_vec_info loop_vinfo)
{
tree phi;
struct loop *loop = LOOP_VINFO_LOOP (loop_vinfo);
basic_block bb = loop->header;
tree dummy;
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, "\n<<vect_analyze_scalar_evolutions>>\n");
for (phi = phi_nodes (bb); phi; phi = TREE_CHAIN (phi))
{
#if 0
int i;
int num_uses;
dataflow_t df;
#endif
tree access_fn = NULL;
if (dump_file && (dump_flags & TDF_DETAILS))
{
fprintf (dump_file, "Analyze phi\n");
print_generic_expr (dump_file, phi, TDF_SLIM);
}
if (!is_gimple_reg (SSA_NAME_VAR (PHI_RESULT (phi))))
{
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, "virtual phi. skip.\n");
continue;
}
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, "analyze cycles: call monev analyzer!\n");
access_fn = instantiate_parameters
(loop,
analyze_scalar_evolution (loop, PHI_RESULT (phi)));
if (!access_fn)
{
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, "No Access function.");
return false;
}
if (dump_file && (dump_flags & TDF_DETAILS))
{
fprintf (dump_file, "Access function of PHI: ");
print_generic_expr (dump_file, access_fn, TDF_SLIM);
}
if (!vect_is_simple_iv_evolution (loop_num (loop), access_fn, &dummy,
&dummy, false))
{
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, "unsupported cross iter cycle.\n");
return false;
}
#if 0
df = get_immediate_uses (phi);
num_uses = num_immediate_uses (df);
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, "num uses = %d\n", num_uses);
for (i = 0; i < num_uses; i++)
{
tree use = immediate_use (df, i);
stmt_vec_info stmt_info = vinfo_for_stmt (use);
if (!stmt_info)
{
if (dump_file && (dump_flags & TDF_DETAILS))
{
fprintf (dump_file, "\nused out side the loop??\n");
print_generic_expr (dump_file, use, TDF_SLIM);
}
return false;
}
if (STMT_VINFO_RELEVANT_P (stmt_info)
&& exist_non_indexing_operands_for_use_p (PHI_RESULT (phi), use))
{
if (dump_file && (dump_flags & TDF_DETAILS))
{
fprintf (dump_file,
"\ninduction vectorization. Unsupported.\n");
print_generic_expr (dump_file, use, TDF_SLIM);
}
return false;
}
}
#endif
}
return true;
}
static bool
vect_analyze_data_ref_dependence (struct data_reference *dra,
struct data_reference *drb)
{
if (!array_base_name_differ_p (dra, drb))
{
enum data_dependence_direction ddd =
ddg_direction_between_stmts (DR_STMT (dra), DR_STMT (drb),
loop_num (loop_of_stmt (DR_STMT (dra))));
if (ddd == dir_independent)
return true;
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file,
"vect_analyze_data_ref_dependence: same base\n");
return false;
}
return true;
}
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);
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, "compare all store-store pairs\n");
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);
bool ok = vect_analyze_data_ref_dependence (dra, drb);
if (!ok)
return false;
}
}
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, "compare all load-store pairs\n");
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);
bool ok = vect_analyze_data_ref_dependence (dra, drb);
if (!ok)
return false;
}
}
return true;
}
static bool
vect_get_array_first_index (tree ref, int *array_first_index)
{
tree array_start;
tree array_base_type;
int array_start_val;
array_base_type = TREE_TYPE (TREE_OPERAND (ref, 0));
if (! TYPE_DOMAIN (array_base_type))
{
if (dump_file && (dump_flags & TDF_DETAILS))
{
fprintf (dump_file, "no domain for array base type\n");
print_generic_expr (dump_file, array_base_type, TDF_DETAILS);
}
return false;
}
array_start = TYPE_MIN_VALUE (TYPE_DOMAIN (array_base_type));
if (TREE_CODE (array_start) != INTEGER_CST)
{
if (dump_file && (dump_flags & TDF_DETAILS))
{
fprintf (dump_file, "array min val not integer cst\n");
print_generic_expr (dump_file, array_start, TDF_DETAILS);
}
return false;
}
if (TREE_INT_CST_HIGH (array_start) != 0)
{
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, "array min val CST_HIGH != 0\n");
return false;
}
array_start_val = TREE_INT_CST_LOW (array_start);
if (dump_file && (dump_flags & TDF_DETAILS))
{
print_generic_expr (dump_file, array_start, TDF_DETAILS);
fprintf (dump_file, "\narray min val = %d\n", array_start_val);
}
*array_first_index = array_start_val;
return true;
}
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);
tree init;
int init_val;
tree scalar_type;
int misalign;
int array_start_val;
bool ok;
DR_MISALIGNMENT (dr) = -1;
if (!vect_force_dr_alignment_p (dr))
return;
init = initial_condition (access_fn);
if (init && TREE_CODE (init) != INTEGER_CST)
{
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, "init not INTEGER_CST\n");
return;
}
if (TREE_INT_CST_HIGH (init) != 0)
{
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, "init CST_HIGH != 0\n");
return;
}
init_val = TREE_INT_CST_LOW (init);
scalar_type = TREE_TYPE (ref);
vectype = get_vectype_for_scalar_type (scalar_type);
if (!vectype)
{
if (dump_file && (dump_flags & TDF_DETAILS))
{
fprintf (dump_file, "no vectype for stmt: ");
print_generic_expr (dump_file, stmt, TDF_SLIM);
fprintf (dump_file, "\nscalar_type: ");
print_generic_expr (dump_file, scalar_type, TDF_DETAILS);
fprintf (dump_file, "\n");
}
return;
}
ok = vect_get_array_first_index (ref, &array_start_val);
if (!ok)
return;
misalign = (init_val - array_start_val) %
GET_MODE_NUNITS (TYPE_MODE (vectype));
DR_MISALIGNMENT (dr) = misalign;
return;
}
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);
}
return;
}
static void
vect_enhance_data_refs_alignment (loop_vec_info loop_vinfo ATTRIBUTE_UNUSED)
{
return;
}
static bool
vect_analyze_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;
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, "\n<<vect_analyze_data_refs_alignment>>\n");
vect_compute_data_refs_alignment (loop_vinfo);
vect_enhance_data_refs_alignment (loop_vinfo);
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 (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, "first access not aligned.\n");
return false;
}
}
if (!targetm.vect.support_misaligned_loads
|| !(*targetm.vect.support_misaligned_loads) ())
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 (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, "first access not aligned.\n");
return false;
}
}
else
for (i = 0; i < VARRAY_ACTIVE_SIZE (loop_read_datarefs); i++)
{
struct data_reference *dr = VARRAY_GENERIC_PTR (loop_read_datarefs, i);
if (DR_MISALIGNMENT (dr) == -1)
{
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, "first access unknown alignment.\n");
return false;
}
}
return true;
}
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;
if (VARRAY_ACTIVE_SIZE (access_fns) != 1)
{
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, "multi dimensional array reference.\n");
return false;
}
access_fn = DR_ACCESS_FN (dr, 0);
if (!vect_is_simple_iv_evolution (loop_num (loop_of_stmt (DR_STMT (dr))),
access_fn, &init, &step, true))
{
if (dump_file && (dump_flags & TDF_DETAILS))
{
fprintf (dump_file, "too complicated access function\n");
print_generic_expr (dump_file, access_fn, TDF_SLIM);
}
return false;
}
return true;
}
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 (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, "\n<<vect_analyze_data_ref_accesses>>\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)
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)
return false;
}
return true;
}
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 (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, "\n<<vect_analyze_data_refs>>\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);
vdef_optype vdefs = STMT_VDEF_OPS (stmt);
vuse_optype vuses = STMT_VUSE_OPS (stmt);
varray_type *datarefs = NULL;
int nvuses = 0, nvdefs = 0;
tree ref = NULL;
tree array_base;
if (!vuses && !vdefs)
continue;
if (vuses)
nvuses = NUM_VUSES (vuses);
if (vdefs)
nvdefs = NUM_VDEFS (vdefs);
if (nvuses + nvdefs != 1)
{
if (dump_file && (dump_flags & TDF_DETAILS))
{
fprintf (dump_file, "Warning: multiple vops!\n");
print_generic_stmt (dump_file, stmt,
~(TDF_RAW | TDF_SLIM | TDF_LINENO));
}
}
if (TREE_CODE (stmt) != MODIFY_EXPR)
{
if (dump_file && (dump_flags & TDF_DETAILS))
{
fprintf (dump_file, "unexpected vops in stmt\n");
print_generic_stmt (dump_file, stmt, TDF_SLIM);
}
return false;
}
if (vuses)
{
if (TREE_CODE (TREE_OPERAND (stmt, 1)) == ARRAY_REF)
{
ref = TREE_OPERAND (stmt, 1);
datarefs = &(LOOP_VINFO_DATAREF_READS (loop_vinfo));
is_read = true;
}
}
if (vdefs)
{
if (TREE_CODE (TREE_OPERAND (stmt, 0)) == ARRAY_REF)
{
ref = TREE_OPERAND (stmt, 0);
datarefs = &(LOOP_VINFO_DATAREF_WRITES (loop_vinfo));
is_read = false;
}
}
if (!ref)
{
if (dump_file && (dump_flags & TDF_DETAILS))
{
fprintf (dump_file, "unhandled non-array data ref\n");
print_generic_stmt (dump_file, stmt, TDF_SLIM);
}
return false;
}
dr = analyze_array (stmt, ref, is_read);
array_base = TREE_OPERAND (ref, 0);
if (TREE_CODE (array_base) == ARRAY_REF)
{
if (dump_file && (dump_flags & TDF_DETAILS))
{
fprintf (dump_file, "unhandled 2D-array data ref\n");
print_generic_stmt (dump_file, stmt, TDF_SLIM);
}
return false;
}
VARRAY_PUSH_GENERIC_PTR (*datarefs, dr);
STMT_VINFO_DATA_REF (stmt_info) = dr;
}
}
return true;
}
static void
vect_mark_relevant (varray_type worklist, tree stmt)
{
stmt_vec_info stmt_info;
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, "mark relevant.\n");
if (TREE_CODE (stmt) == PHI_NODE)
{
VARRAY_PUSH_TREE (worklist, stmt);
return;
}
stmt_info = vinfo_for_stmt (stmt);
if (!stmt_info)
{
if (dump_file && (dump_flags & TDF_DETAILS))
{
fprintf (dump_file, "mark relevant: no stmt info!!\n");
print_generic_expr (dump_file, stmt, TDF_SLIM);
}
return;
}
if (STMT_VINFO_RELEVANT_P (stmt_info))
{
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, "already marked relevant.\n");
return;
}
STMT_VINFO_RELEVANT_P (stmt_info) = 1;
VARRAY_PUSH_TREE (worklist, stmt);
}
static bool
vect_stmt_relevant_p (tree stmt, loop_vec_info loop_vinfo)
{
vdef_optype vdefs;
struct loop *loop = LOOP_VINFO_LOOP (loop_vinfo);
int i;
dataflow_t df;
int num_uses;
if (is_ctrl_stmt (stmt) && (stmt != LOOP_VINFO_EXIT_COND (loop_vinfo)))
return true;
vdefs = STMT_VDEF_OPS (stmt);
if (vdefs)
{
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, "vec_stmt_relevant_p: stmt has vdefs:\n");
return true;
}
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 (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file,
"vec_stmt_relevant_p: used out of loop:\n");
return true;
}
}
return false;
}
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 (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, "\n<<vect_mark_stmts_to_be_vectorized>>\n");
VARRAY_TREE_INIT (worklist, 64, "work list");
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 (dump_file && (dump_flags & TDF_DETAILS))
{
fprintf (dump_file, "init: stmt relevant?\n");
print_generic_stmt (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);
}
}
while (VARRAY_ACTIVE_SIZE (worklist) > 0)
{
stmt = VARRAY_TOP_TREE (worklist);
VARRAY_POP (worklist);
if (dump_file && (dump_flags & TDF_DETAILS))
{
fprintf (dump_file, "worklist: examine stmt:\n");
print_generic_stmt (dump_file, stmt, TDF_SLIM);
}
if (TREE_CODE (stmt) == PHI_NODE)
{
for (j = 0; j < PHI_NUM_ARGS (stmt); j++)
{
tree arg = PHI_ARG_DEF (stmt, j);
if (TREE_CODE (arg) == SSA_NAME)
{
tree def_stmt = NULL_TREE;
basic_block bb;
if (TREE_CODE (arg) == SSA_NAME)
def_stmt = SSA_NAME_DEF_STMT (arg);
if (def_stmt == NULL_TREE )
{
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, "\nworklist: no def_stmt!\n");
varray_clear (worklist);
return false;
}
if (TREE_CODE (def_stmt) == NOP_EXPR)
{
tree arg = TREE_OPERAND (def_stmt, 0);
if (TREE_CODE (arg) != INTEGER_CST
&& TREE_CODE (arg) != REAL_CST)
{
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, "\nworklist: NOP def_stmt?\n");
varray_clear (worklist);
return false;
}
continue;
}
if (dump_file && (dump_flags & TDF_DETAILS))
{
fprintf (dump_file, "\nworklist: def_stmt:\n");
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);
}
}
continue;
}
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);
if (dump_file && (dump_flags & TDF_DETAILS))
{
fprintf (dump_file, "\nworklist: examine use %d:\n", i);
print_generic_expr (dump_file, use, TDF_SLIM);
}
if (exist_non_indexing_operands_for_use_p (use, stmt))
{
tree def_stmt = NULL_TREE;
basic_block bb;
if (TREE_CODE (use) == SSA_NAME)
def_stmt = SSA_NAME_DEF_STMT (use);
if (def_stmt == NULL_TREE)
{
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, "\nworklist: no def_stmt!\n");
varray_clear (worklist);
return false;
}
if (TREE_CODE (def_stmt) == NOP_EXPR)
{
tree arg = TREE_OPERAND (def_stmt, 0);
if (TREE_CODE (arg) != INTEGER_CST
&& TREE_CODE (arg) != REAL_CST)
{
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, "\nworklist: NOP def_stmt?\n");
varray_clear (worklist);
return false;
}
continue;
}
if (dump_file && (dump_flags & TDF_DETAILS))
{
fprintf (dump_file, "\nworklist: def_stmt:\n");
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);
}
}
}
varray_clear (worklist);
return true;
}
static bool
vect_analyze_loop_with_symbolic_num_of_iters (tree *symb_num_of_iters,
struct loop *loop)
{
tree niters;
basic_block bb = loop->header;
tree phi;
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, "\n<<vect_analyze_loop_with_symbolic_num_of_iters>>\n");
niters = number_of_iterations_in_loop (loop);
if (niters == NULL_TREE || niters == chrec_top)
{
struct tree_niter_desc niter_desc;
if (number_of_iterations_exit
(loop, loop_exit_edge (loop, 0), &niter_desc))
niters = build (PLUS_EXPR, TREE_TYPE (niter_desc.niter),
niter_desc.niter, integer_one_node);
}
if (niters == chrec_top)
{
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, "\nInfinite number of iterations.\n");
return false;
}
if (!niters)
{
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, "\nniters is NULL poiter.\n");
return false;
}
if (dump_file && (dump_flags & TDF_DETAILS))
{
fprintf (dump_file, "\nSymbolic number of iterations is ");
print_generic_expr (dump_file, niters, TDF_DETAILS);
}
if (chrec_contains_intervals (niters))
{
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, "\nniters contains interval.\n");
return false;
}
for (phi = phi_nodes (bb); phi; phi = TREE_CHAIN (phi))
{
tree access_fn = NULL;
tree evolution_part;
if (dump_file && (dump_flags & TDF_DETAILS))
{
fprintf (dump_file, "\nAnalyze phi\n");
print_generic_expr (dump_file, phi, TDF_SLIM);
}
if (!is_gimple_reg (SSA_NAME_VAR (PHI_RESULT (phi))))
{
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, "virtual phi. skip.\n");
continue;
}
access_fn = instantiate_parameters
(loop,
analyze_scalar_evolution (loop, PHI_RESULT (phi)));
if (!access_fn)
{
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, "No Access function.");
return false;
}
if (dump_file && (dump_flags & TDF_DETAILS))
{
fprintf (dump_file, "Access function of PHI: ");
print_generic_expr (dump_file, access_fn, TDF_SLIM);
}
evolution_part = evolution_part_in_loop_num (access_fn, loop_num(loop));
if (evolution_part == NULL_TREE)
return false;
if (TREE_CODE (evolution_part) == POLYNOMIAL_CHREC
|| TREE_CODE (evolution_part) == EXPONENTIAL_CHREC)
return false;
}
*symb_num_of_iters = niters;
return true;
}
static tree
vect_get_loop_niters (struct loop *loop, int *number_of_iterations)
{
tree niters;
tree loop_exit;
bool analyzable_loop_bound = false;
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, "\n<<get_loop_niters>>\n");
loop_exit = get_loop_exit_condition (loop);
niters = number_of_iterations_in_loop (loop);
if (niters != NULL_TREE && niters != chrec_top)
{
if (dump_file && (dump_flags & TDF_DETAILS))
{
fprintf (dump_file, "scev niters: ");
print_generic_expr (dump_file, niters, TDF_SLIM);
}
if (TREE_CODE (niters) == INTEGER_CST)
*number_of_iterations = TREE_INT_CST_LOW (niters);
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, "scev niters: %d\n", *number_of_iterations);
analyzable_loop_bound = true;
}
else
{
struct tree_niter_desc niter_desc;
if (number_of_iterations_exit
(loop, loop_exit_edge (loop, 0), &niter_desc))
{
if (dump_file && (dump_flags & TDF_DETAILS))
{
fprintf (dump_file, "number_of_iterations_exit: ");
print_generic_expr (dump_file, niter_desc.niter, TDF_SLIM);
}
if (TREE_CODE (niter_desc.niter) == INTEGER_CST)
{
int niters = TREE_INT_CST_LOW (niter_desc.niter);
*number_of_iterations = niters + 1;
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file,
"number_of_iterations_exit: %d\n", *number_of_iterations);
}
analyzable_loop_bound = true;
}
}
return loop_exit;
}
static loop_vec_info
vect_analyze_loop_form (struct loop *loop)
{
loop_vec_info loop_vinfo;
tree loop_cond;
int number_of_iterations = -1;
tree symb_num_of_iters = NULL_TREE;
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, "\n<<vect_analyze_loop_form>>\n");
if (loop->level > 1
|| loop->num_exits > 1 || loop->num_entries > 1
|| !loop->pre_header || !loop->header || !loop->latch)
{
if (dump_file && (dump_flags & TDF_DETAILS))
{
fprintf (dump_file,
"loop_analyzer: bad loop form (entry/exit, nbbs, level...)\n");
flow_loop_dump (loop, dump_file, NULL, 1);
}
return NULL;
}
loop_cond = vect_get_loop_niters (loop, &number_of_iterations);
if (!loop_cond)
{
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, "Complicated exit condition.\n");
return NULL;
}
if (number_of_iterations > 0 && second_loop_vers_available)
if_converted_loop = tree_if_conversion (loop, true);
if (loop->num_nodes != 3 && loop->num_nodes != 2)
{
if (dump_file && (dump_flags & TDF_DETAILS))
{
fprintf (dump_file,
"loop_analyzer: bad loop form (no of nodes...)\n");
flow_loop_dump (loop, dump_file, NULL, 1);
}
return NULL;
}
if (number_of_iterations < 0)
{
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, "Can't determine num iters.\n");
if (if_converted_loop)
{
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, "Can't handle unknown loop bound in if converted loop.\n");
return NULL;
}
if(!vect_analyze_loop_with_symbolic_num_of_iters (&symb_num_of_iters, loop))
{
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, "Can't determine loop bound.\n");
return NULL;
}
}
if (number_of_iterations == 0)
{
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, "0 iterations??\n");
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;
LOOP_VINFO_SYMB_NUM_OF_ITERS(loop_vinfo) = symb_num_of_iters;
return loop_vinfo;
}
static loop_vec_info
vect_analyze_loop (struct loop *loop)
{
bool ok;
loop_vec_info loop_vinfo;
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, "\n\n\n<<<<<<< analyze_loop_nest >>>>>>>\n");
loop_vinfo = vect_analyze_loop_form (loop);
if (!loop_vinfo)
{
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, "loop_analyzer: bad loop form.\n");
return NULL;
}
ok = vect_analyze_data_refs (loop_vinfo);
if (!ok)
{
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, "loop_analyzer: bad data references.\n");
destroy_loop_vec_info (loop_vinfo);
return NULL;
}
ok = vect_mark_stmts_to_be_vectorized (loop_vinfo);
if (!ok)
{
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, "loop_analyzer: unexpected pattern.\n");
destroy_loop_vec_info (loop_vinfo);
return NULL;
}
ok = vect_analyze_scalar_cycles (loop_vinfo);
if (!ok)
{
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, "loop_analyzer: bad scalar cycle.\n");
destroy_loop_vec_info (loop_vinfo);
return NULL;
}
ok = vect_analyze_data_ref_dependences (loop_vinfo);
if (!ok)
{
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, "loop_analyzer: bad data dependence.\n");
destroy_loop_vec_info (loop_vinfo);
return NULL;
}
ok = vect_analyze_data_ref_accesses (loop_vinfo);
if (!ok)
{
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, "loop_analyzer: bad data access.\n");
destroy_loop_vec_info (loop_vinfo);
return NULL;
}
ok = vect_analyze_data_refs_alignment (loop_vinfo);
if (!ok)
{
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, "loop_analyzer: bad data alignment.\n");
destroy_loop_vec_info (loop_vinfo);
return NULL;
}
ok = vect_analyze_operations (loop_vinfo);
if (!ok)
{
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, "loop_analyzer: bad operations.\n");
destroy_loop_vec_info (loop_vinfo);
return NULL;
}
LOOP_VINFO_VECTORIZABLE_P (loop_vinfo) = 1;
return loop_vinfo;
}
static bool
need_imm_uses_for (tree var)
{
return is_gimple_reg (var);
}
static void
vect_loop_version (struct loops *loops, struct loop *loop, basic_block *bb)
{
tree cond_expr;
struct loop *nloop;
cond_expr = build (EQ_EXPR, boolean_type_node,
integer_one_node, integer_one_node);
nloop = tree_ssa_loop_version (loops, loop, cond_expr, bb);
if (nloop)
second_loop_vers_available = true;
else
second_loop_vers_available = false;
}
void
vectorize_loops (struct loops *loops)
{
unsigned int i, loops_num;
unsigned int num_vectorized_loops = 0;
if (!UNITS_PER_SIMD_WORD)
{
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file,
"vectorizer: target vector size is not defined.\n");
return;
}
compute_immediate_uses (TDFA_USE_OPS, need_imm_uses_for);
loops_num = loops->num;
for (i = 1; i < loops_num; i++)
{
loop_vec_info loop_vinfo;
basic_block bb;
struct loop *loop = loops->parray[i];
vect_loop_version (loops, loop, &bb);
if_converted_loop = false;
flow_loop_scan (loop, LOOP_ALL);
loop_vinfo = vect_analyze_loop (loop);
loop->aux = loop_vinfo;
#ifndef ANALYZE_ALL_THEN_VECTORIZE_ALL
if (!loop_vinfo || !LOOP_VINFO_VECTORIZABLE_P (loop_vinfo))
{
if (second_loop_vers_available)
{
if (dump_file && (dump_flags & TDF_STATS))
fprintf (dump_file, "removing second loop version.\n");
update_lv_condition (&bb, boolean_false_node);
}
continue;
}
if (second_loop_vers_available)
{
if (dump_file && (dump_flags & TDF_STATS))
fprintf (dump_file, "vectorizing first loop version.\n");
}
vect_transform_loop (loop_vinfo, loops);
num_vectorized_loops++;
if (second_loop_vers_available)
{
if_converted_loop = false;
rewrite_into_ssa (false);
bitmap_clear (vars_to_rename);
rewrite_into_loop_closed_ssa ();
}
#endif
}
#ifdef ANALYZE_ALL_THEN_VECTORIZE_ALL
for (i = 1; i < loops_num; i++)
{
struct loop *loop = loops->parray[i];
loop_vec_info loop_vinfo = loop->aux;
if (!loop_vinfo || !LOOP_VINFO_VECTORIZABLE_P (loop_vinfo))
continue;
vect_transform_loop (loop_vinfo,loops);
num_vectorized_loops++;
}
#endif
if (dump_file && (dump_flags & TDF_STATS))
fprintf (dump_file, "vectorized %u loops in function.\n",
num_vectorized_loops);
free_df ();
for (i = 1; i < loops_num; i++)
{
struct loop *loop = loops->parray[i];
loop_vec_info loop_vinfo = loop->aux;
destroy_loop_vec_info (loop_vinfo);
loop->aux = NULL;
}
}