/* Analysis Utilities for Loop Vectorization.
- Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011
+ Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012
Free Software Foundation, Inc.
Contributed by Dorit Nuzman <dorit@il.ibm.com>
vect_recog_widen_sum_pattern,
vect_recog_dot_prod_pattern,
vect_recog_pow_pattern,
- vect_recog_over_widening_pattern,
vect_recog_widen_shift_pattern,
+ vect_recog_over_widening_pattern,
vect_recog_vector_vector_shift_pattern,
vect_recog_sdivmod_pow2_pattern,
vect_recog_mixed_size_cond_pattern,
append_pattern_def_seq (stmt_info, stmt);
}
+/* If the LHS of DEF_STMT has a single use, and that statement is
+ in the same loop, return it. */
+
+static gimple
+vect_single_imm_use (gimple def_stmt)
+{
+ stmt_vec_info stmt_vinfo = vinfo_for_stmt (def_stmt);
+ loop_vec_info loop_vinfo = STMT_VINFO_LOOP_VINFO (stmt_vinfo);
+ struct loop *loop = LOOP_VINFO_LOOP (loop_vinfo);
+ tree lhs = gimple_assign_lhs (def_stmt);
+ use_operand_p use_p;
+ gimple use_stmt;
+
+ if (!single_imm_use (lhs, &use_p, &use_stmt))
+ return NULL;
+
+ if (!gimple_bb (use_stmt))
+ return NULL;
+
+ if (!flow_bb_inside_loop_p (loop, gimple_bb (use_stmt)))
+ return NULL;
+
+ gcc_assert (vinfo_for_stmt (use_stmt));
+ return use_stmt;
+}
+
/* Function widened_name_p
Check whether NAME, an ssa-name used in USE_STMT,
stmt_vinfo = vinfo_for_stmt (use_stmt);
loop_vinfo = STMT_VINFO_LOOP_VINFO (stmt_vinfo);
- if (!vect_is_simple_use (name, loop_vinfo, NULL, def_stmt, &def, &dt))
+ if (!vect_is_simple_use (name, use_stmt, loop_vinfo, NULL, def_stmt, &def,
+ &dt))
return false;
if (dt != vect_internal_def
|| (TYPE_PRECISION (type) < (TYPE_PRECISION (*half_type) * 2)))
return false;
- if (!vect_is_simple_use (oprnd0, loop_vinfo, NULL, &dummy_gimple, &dummy,
- &dt))
+ if (!vect_is_simple_use (oprnd0, *def_stmt, loop_vinfo,
+ NULL, &dummy_gimple, &dummy, &dt))
return false;
return true;
Use unsigned TYPE as the type for WIDEN_MULT_EXPR. */
if (TYPE_UNSIGNED (type) != TYPE_UNSIGNED (half_type0))
{
- tree lhs = gimple_assign_lhs (last_stmt), use_lhs;
- imm_use_iterator imm_iter;
- use_operand_p use_p;
- int nuses = 0;
- gimple use_stmt = NULL;
+ gimple use_stmt;
+ tree use_lhs;
tree use_type;
if (TYPE_UNSIGNED (type) == TYPE_UNSIGNED (half_type1))
return NULL;
- FOR_EACH_IMM_USE_FAST (use_p, imm_iter, lhs)
- {
- if (is_gimple_debug (USE_STMT (use_p)))
- continue;
- use_stmt = USE_STMT (use_p);
- nuses++;
- }
-
- if (nuses != 1 || !is_gimple_assign (use_stmt)
+ use_stmt = vect_single_imm_use (last_stmt);
+ if (!use_stmt || !is_gimple_assign (use_stmt)
|| gimple_assign_rhs_code (use_stmt) != NOP_EXPR)
return NULL;
|| TREE_CODE (const_oprnd) != INTEGER_CST)
return false;
+ /* If oprnd has other uses besides that in stmt we cannot mark it
+ as being part of a pattern only. */
+ if (!has_single_use (oprnd))
+ return false;
+
/* If we are in the middle of a sequence, we use DEF from a previous
statement. Otherwise, OPRND has to be a result of type promotion. */
if (*new_type)
{
gimple stmt = VEC_pop (gimple, *stmts);
gimple pattern_stmt = NULL, new_def_stmt, prev_stmt = NULL, use_stmt = NULL;
- tree op0, op1, vectype = NULL_TREE, lhs, use_lhs, use_type;
- imm_use_iterator imm_iter;
- use_operand_p use_p;
- int nuses = 0;
+ tree op0, op1, vectype = NULL_TREE, use_lhs, use_type;
tree var = NULL_TREE, new_type = NULL_TREE, tmp, new_oprnd;
bool first;
- struct loop *loop = (gimple_bb (stmt))->loop_father;
tree type = NULL;
first = true;
}
/* STMT can be performed on a smaller type. Check its uses. */
- lhs = gimple_assign_lhs (stmt);
- nuses = 0;
- FOR_EACH_IMM_USE_FAST (use_p, imm_iter, lhs)
- {
- if (is_gimple_debug (USE_STMT (use_p)))
- continue;
- use_stmt = USE_STMT (use_p);
- nuses++;
- }
-
- if (nuses != 1 || !is_gimple_assign (use_stmt)
- || !gimple_bb (use_stmt)
- || !flow_bb_inside_loop_p (loop, gimple_bb (use_stmt)))
+ use_stmt = vect_single_imm_use (stmt);
+ if (!use_stmt || !is_gimple_assign (use_stmt))
return NULL;
/* Create pattern statement for STMT. */
{
use_lhs = gimple_assign_lhs (use_stmt);
use_type = TREE_TYPE (use_lhs);
- /* Support only type promotion or signedess change. Check that USE_TYPE
- is not bigger than the original type. */
+ /* Support only type demotion or signedess change. */
if (!INTEGRAL_TYPE_P (use_type)
- || TYPE_PRECISION (new_type) > TYPE_PRECISION (use_type)
- || TYPE_PRECISION (type) < TYPE_PRECISION (use_type))
+ || TYPE_PRECISION (type) <= TYPE_PRECISION (use_type))
return NULL;
+ /* Check that NEW_TYPE is not bigger than the conversion result. */
+ if (TYPE_PRECISION (new_type) > TYPE_PRECISION (use_type))
+ return NULL;
+
if (TYPE_UNSIGNED (new_type) != TYPE_UNSIGNED (use_type)
|| TYPE_PRECISION (new_type) != TYPE_PRECISION (use_type))
{
where type 'TYPE' is at least double the size of type 'type'.
- Also detect unsigned cases:
+ Also detect cases where the shift result is immediately converted
+ to another type 'result_type' that is no larger in size than 'TYPE'.
+ In those cases we perform a widen-shift that directly results in
+ 'result_type', to avoid a possible over-widening situation:
- unsigned type a_t;
- unsigned TYPE u_res_T;
+ type a_t;
TYPE a_T, res_T;
+ result_type res_result;
S1 a_t = ;
S2 a_T = (TYPE) a_t;
S3 res_T = a_T << CONST;
- S4 u_res_T = (unsigned TYPE) res_T;
+ S4 res_result = (result_type) res_T;
+ '--> res_result' = a_t w<< CONST;
And a case when 'TYPE' is 4 times bigger than 'type'. In that case we
create an additional pattern stmt for S2 to create a variable of an
gimple def_stmt0;
tree oprnd0, oprnd1;
tree type, half_type0;
- gimple pattern_stmt, orig_stmt = NULL;
+ gimple pattern_stmt;
tree vectype, vectype_out = NULL_TREE;
tree dummy;
tree var;
enum tree_code dummy_code;
int dummy_int;
VEC (tree, heap) * dummy_vec;
- gimple use_stmt = NULL;
- bool over_widen = false;
+ gimple use_stmt;
if (!is_gimple_assign (last_stmt) || !vinfo_for_stmt (last_stmt))
return NULL;
- orig_stmt = last_stmt;
if (STMT_VINFO_IN_PATTERN_P (vinfo_for_stmt (last_stmt)))
- {
- /* This statement was also detected as over-widening operation (it can't
- be any other pattern, because only over-widening detects shifts).
- LAST_STMT is the final type demotion statement, but its related
- statement is shift. We analyze the related statement to catch cases:
-
- orig code:
- type a_t;
- itype res;
- TYPE a_T, res_T;
-
- S1 a_T = (TYPE) a_t;
- S2 res_T = a_T << CONST;
- S3 res = (itype)res_T;
-
- (size of type * 2 <= size of itype
- and size of itype * 2 <= size of TYPE)
-
- code after over-widening pattern detection:
-
- S1 a_T = (TYPE) a_t;
- --> a_it = (itype) a_t;
- S2 res_T = a_T << CONST;
- S3 res = (itype)res_T; <--- LAST_STMT
- --> res = a_it << CONST;
-
- after widen_shift:
-
- S1 a_T = (TYPE) a_t;
- --> a_it = (itype) a_t; - redundant
- S2 res_T = a_T << CONST;
- S3 res = (itype)res_T;
- --> res = a_t w<< CONST;
-
- i.e., we replace the three statements with res = a_t w<< CONST. */
- last_stmt = STMT_VINFO_RELATED_STMT (vinfo_for_stmt (last_stmt));
- over_widen = true;
- }
+ return NULL;
if (gimple_assign_rhs_code (last_stmt) != LSHIFT_EXPR)
return NULL;
oprnd0 = gimple_assign_rhs1 (def_stmt0);
type = gimple_expr_type (last_stmt);
+ /* Check for subsequent conversion to another type. */
+ use_stmt = vect_single_imm_use (last_stmt);
+ if (use_stmt && is_gimple_assign (use_stmt)
+ && CONVERT_EXPR_CODE_P (gimple_assign_rhs_code (use_stmt))
+ && !STMT_VINFO_IN_PATTERN_P (vinfo_for_stmt (use_stmt)))
+ {
+ tree use_lhs = gimple_assign_lhs (use_stmt);
+ tree use_type = TREE_TYPE (use_lhs);
+
+ if (INTEGRAL_TYPE_P (use_type)
+ && TYPE_PRECISION (use_type) <= TYPE_PRECISION (type))
+ {
+ last_stmt = use_stmt;
+ type = use_type;
+ }
+ }
+
/* Check if this a widening operation. */
if (!vect_handle_widen_op_by_const (last_stmt, LSHIFT_EXPR, oprnd1,
&oprnd0, stmts,
type, &half_type0, def_stmt0))
return NULL;
- /* Handle unsigned case. Look for
- S4 u_res_T = (unsigned TYPE) res_T;
- Use unsigned TYPE as the type for WIDEN_LSHIFT_EXPR. */
- if (TYPE_UNSIGNED (type) != TYPE_UNSIGNED (half_type0))
- {
- tree lhs = gimple_assign_lhs (last_stmt), use_lhs;
- imm_use_iterator imm_iter;
- use_operand_p use_p;
- int nuses = 0;
- tree use_type;
-
- if (over_widen)
- {
- /* In case of over-widening pattern, S4 should be ORIG_STMT itself.
- We check here that TYPE is the correct type for the operation,
- i.e., it's the type of the original result. */
- tree orig_type = gimple_expr_type (orig_stmt);
- if ((TYPE_UNSIGNED (type) != TYPE_UNSIGNED (orig_type))
- || (TYPE_PRECISION (type) != TYPE_PRECISION (orig_type)))
- return NULL;
- }
- else
- {
- FOR_EACH_IMM_USE_FAST (use_p, imm_iter, lhs)
- {
- if (is_gimple_debug (USE_STMT (use_p)))
- continue;
- use_stmt = USE_STMT (use_p);
- nuses++;
- }
-
- if (nuses != 1 || !is_gimple_assign (use_stmt)
- || !CONVERT_EXPR_CODE_P (gimple_assign_rhs_code (use_stmt)))
- return NULL;
-
- use_lhs = gimple_assign_lhs (use_stmt);
- use_type = TREE_TYPE (use_lhs);
-
- if (!INTEGRAL_TYPE_P (use_type)
- || (TYPE_UNSIGNED (type) == TYPE_UNSIGNED (use_type))
- || (TYPE_PRECISION (type) != TYPE_PRECISION (use_type)))
- return NULL;
-
- type = use_type;
- }
- }
-
/* Pattern detected. */
if (vect_print_dump_info (REPORT_DETAILS))
fprintf (vect_dump, "vect_recog_widen_shift_pattern: detected: ");
if (vect_print_dump_info (REPORT_DETAILS))
print_gimple_stmt (vect_dump, pattern_stmt, 0, TDF_SLIM);
- if (use_stmt)
- last_stmt = use_stmt;
- else
- last_stmt = orig_stmt;
-
VEC_safe_push (gimple, heap, *stmts, last_stmt);
return pattern_stmt;
}
!= TYPE_PRECISION (TREE_TYPE (oprnd0)))
return NULL;
- if (!vect_is_simple_use (oprnd1, loop_vinfo, NULL, &def_stmt, &def, &dt))
+ if (!vect_is_simple_use (oprnd1, last_stmt, loop_vinfo, NULL, &def_stmt,
+ &def, &dt))
return NULL;
if (dt != vect_internal_def)
tree def, rhs1;
enum tree_code rhs_code;
- if (!vect_is_simple_use (var, loop_vinfo, NULL, &def_stmt, &def, &dt))
+ if (!vect_is_simple_use (var, NULL, loop_vinfo, NULL, &def_stmt, &def, &dt))
return false;
if (dt != vect_internal_def)
{
tree vecitype, comp_vectype;
+ /* If the comparison can throw, then is_gimple_condexpr will be
+ false and we can't make a COND_EXPR/VEC_COND_EXPR out of it. */
+ if (stmt_could_throw_p (def_stmt))
+ return false;
+
comp_vectype = get_vectype_for_scalar_type (TREE_TYPE (rhs1));
if (comp_vectype == NULL_TREE)
return false;
default:
gcc_assert (TREE_CODE_CLASS (rhs_code) == tcc_comparison);
if (TREE_CODE (TREE_TYPE (rhs1)) != INTEGER_TYPE
- || !TYPE_UNSIGNED (TREE_TYPE (rhs1)))
+ || !TYPE_UNSIGNED (TREE_TYPE (rhs1))
+ || (TYPE_PRECISION (TREE_TYPE (rhs1))
+ != GET_MODE_BITSIZE (TYPE_MODE (TREE_TYPE (rhs1)))))
{
enum machine_mode mode = TYPE_MODE (TREE_TYPE (rhs1));
itype