/* Analysis Utilities for Loop Vectorization.
- Copyright (C) 2006 Free Software Foundation, Inc.
+ Copyright (C) 2006, 2007 Free Software Foundation, Inc.
Contributed by Dorit Nuzman <dorit@il.ibm.com>
This file is part of GCC.
static tree vect_recog_widen_sum_pattern (tree, tree *, tree *);
static tree vect_recog_widen_mult_pattern (tree, tree *, tree *);
static tree vect_recog_dot_prod_pattern (tree, tree *, tree *);
+static tree vect_recog_pow_pattern (tree, tree *, tree *);
static vect_recog_func_ptr vect_vect_recog_func_ptrs[NUM_PATTERNS] = {
vect_recog_widen_mult_pattern,
vect_recog_widen_sum_pattern,
- vect_recog_dot_prod_pattern};
+ vect_recog_dot_prod_pattern,
+ vect_recog_pow_pattern};
/* Function widened_name_p
if (! *def_stmt)
return false;
- if (TREE_CODE (*def_stmt) != MODIFY_EXPR)
+ if (TREE_CODE (*def_stmt) != GIMPLE_MODIFY_STMT)
return false;
- expr = TREE_OPERAND (*def_stmt, 1);
+ expr = GIMPLE_STMT_OPERAND (*def_stmt, 1);
if (TREE_CODE (expr) != NOP_EXPR)
return false;
if (!vect_is_simple_use (oprnd0, loop_vinfo, &dummy, &dummy, &dt))
return false;
- if (dt != vect_invariant_def && dt != vect_constant_def
- && dt != vect_loop_def)
- return false;
-
return true;
}
tree pattern_expr;
tree prod_type;
- if (TREE_CODE (last_stmt) != MODIFY_EXPR)
+ if (TREE_CODE (last_stmt) != GIMPLE_MODIFY_STMT)
return NULL;
- expr = TREE_OPERAND (last_stmt, 1);
+ expr = GIMPLE_STMT_OPERAND (last_stmt, 1);
type = TREE_TYPE (expr);
/* Look for the following pattern
/* Has been detected as widening-summation? */
stmt = STMT_VINFO_RELATED_STMT (stmt_vinfo);
- expr = TREE_OPERAND (stmt, 1);
+ expr = GIMPLE_STMT_OPERAND (stmt, 1);
type = TREE_TYPE (expr);
if (TREE_CODE (expr) != WIDEN_SUM_EXPR)
return NULL;
if (widened_name_p (oprnd0, stmt, &half_type, &def_stmt))
{
stmt = def_stmt;
- expr = TREE_OPERAND (stmt, 1);
+ expr = GIMPLE_STMT_OPERAND (stmt, 1);
oprnd0 = TREE_OPERAND (expr, 0);
}
else
gcc_assert (stmt_vinfo);
if (STMT_VINFO_DEF_TYPE (stmt_vinfo) != vect_loop_def)
return NULL;
- expr = TREE_OPERAND (stmt, 1);
+ expr = GIMPLE_STMT_OPERAND (stmt, 1);
if (TREE_CODE (expr) != MULT_EXPR)
return NULL;
if (STMT_VINFO_IN_PATTERN_P (stmt_vinfo))
/* Has been detected as a widening multiplication? */
stmt = STMT_VINFO_RELATED_STMT (stmt_vinfo);
- expr = TREE_OPERAND (stmt, 1);
+ expr = GIMPLE_STMT_OPERAND (stmt, 1);
if (TREE_CODE (expr) != WIDEN_MULT_EXPR)
return NULL;
stmt_vinfo = vinfo_for_stmt (stmt);
return NULL;
if (!widened_name_p (oprnd0, stmt, &half_type0, &def_stmt))
return NULL;
- oprnd00 = TREE_OPERAND (TREE_OPERAND (def_stmt, 1), 0);
+ oprnd00 = TREE_OPERAND (GIMPLE_STMT_OPERAND (def_stmt, 1), 0);
if (!widened_name_p (oprnd1, stmt, &half_type1, &def_stmt))
return NULL;
- oprnd01 = TREE_OPERAND (TREE_OPERAND (def_stmt, 1), 0);
+ oprnd01 = TREE_OPERAND (GIMPLE_STMT_OPERAND (def_stmt, 1), 0);
if (TYPE_MAIN_VARIANT (half_type0) != TYPE_MAIN_VARIANT (half_type1))
return NULL;
if (TYPE_PRECISION (prod_type) != TYPE_PRECISION (half_type0) * 2)
*/
static tree
-vect_recog_widen_mult_pattern (tree last_stmt ATTRIBUTE_UNUSED,
- tree *type_in ATTRIBUTE_UNUSED,
- tree *type_out ATTRIBUTE_UNUSED)
+vect_recog_widen_mult_pattern (tree last_stmt,
+ tree *type_in,
+ tree *type_out)
{
- /* Yet to be implemented. */
- return NULL;
+ tree expr;
+ tree def_stmt0, def_stmt1;
+ tree oprnd0, oprnd1;
+ tree type, half_type0, half_type1;
+ tree pattern_expr;
+ tree vectype;
+ tree dummy;
+ enum tree_code dummy_code;
+
+ if (TREE_CODE (last_stmt) != GIMPLE_MODIFY_STMT)
+ return NULL;
+
+ expr = GIMPLE_STMT_OPERAND (last_stmt, 1);
+ type = TREE_TYPE (expr);
+
+ /* Starting from LAST_STMT, follow the defs of its uses in search
+ of the above pattern. */
+
+ if (TREE_CODE (expr) != MULT_EXPR)
+ return NULL;
+
+ oprnd0 = TREE_OPERAND (expr, 0);
+ oprnd1 = TREE_OPERAND (expr, 1);
+ if (TYPE_MAIN_VARIANT (TREE_TYPE (oprnd0)) != TYPE_MAIN_VARIANT (type)
+ || TYPE_MAIN_VARIANT (TREE_TYPE (oprnd1)) != TYPE_MAIN_VARIANT (type))
+ return NULL;
+
+ /* Check argument 0 */
+ if (!widened_name_p (oprnd0, last_stmt, &half_type0, &def_stmt0))
+ return NULL;
+ oprnd0 = TREE_OPERAND (GIMPLE_STMT_OPERAND (def_stmt0, 1), 0);
+
+ /* Check argument 1 */
+ if (!widened_name_p (oprnd1, last_stmt, &half_type1, &def_stmt1))
+ return NULL;
+ oprnd1 = TREE_OPERAND (GIMPLE_STMT_OPERAND (def_stmt1, 1), 0);
+
+ if (TYPE_MAIN_VARIANT (half_type0) != TYPE_MAIN_VARIANT (half_type1))
+ return NULL;
+
+ /* Pattern detected. */
+ if (vect_print_dump_info (REPORT_DETAILS))
+ fprintf (vect_dump, "vect_recog_widen_mult_pattern: detected: ");
+
+ /* Check target support */
+ vectype = get_vectype_for_scalar_type (half_type0);
+ if (!vectype
+ || !supportable_widening_operation (WIDEN_MULT_EXPR, last_stmt, vectype,
+ &dummy, &dummy, &dummy_code,
+ &dummy_code))
+ return NULL;
+
+ *type_in = vectype;
+ *type_out = NULL_TREE;
+
+ /* Pattern supported. Create a stmt to be used to replace the pattern: */
+ pattern_expr = build2 (WIDEN_MULT_EXPR, type, oprnd0, oprnd1);
+ if (vect_print_dump_info (REPORT_DETAILS))
+ print_generic_expr (vect_dump, pattern_expr, TDF_SLIM);
+ return pattern_expr;
+}
+
+
+/* Function vect_recog_pow_pattern
+
+ Try to find the following pattern:
+
+ x = POW (y, N);
+
+ with POW being one of pow, powf, powi, powif and N being
+ either 2 or 0.5.
+
+ Input:
+
+ * LAST_STMT: A stmt from which the pattern search begins.
+
+ Output:
+
+ * TYPE_IN: The type of the input arguments to the pattern.
+
+ * TYPE_OUT: The type of the output of this pattern.
+
+ * Return value: A new stmt that will be used to replace the sequence of
+ stmts that constitute the pattern. In this case it will be:
+ x * x
+ or
+ sqrt (x)
+*/
+
+static tree
+vect_recog_pow_pattern (tree last_stmt, tree *type_in, tree *type_out)
+{
+ tree expr;
+ tree type;
+ tree fn, base, exp;
+
+ if (TREE_CODE (last_stmt) != GIMPLE_MODIFY_STMT)
+ return NULL;
+
+ expr = GIMPLE_STMT_OPERAND (last_stmt, 1);
+ type = TREE_TYPE (expr);
+
+ if (TREE_CODE (expr) != CALL_EXPR)
+ return NULL_TREE;
+
+ fn = get_callee_fndecl (expr);
+ switch (DECL_FUNCTION_CODE (fn))
+ {
+ case BUILT_IN_POWIF:
+ case BUILT_IN_POWI:
+ case BUILT_IN_POWF:
+ case BUILT_IN_POW:
+ base = CALL_EXPR_ARG (expr, 0);
+ exp = CALL_EXPR_ARG (expr, 1);
+ if (TREE_CODE (exp) != REAL_CST
+ && TREE_CODE (exp) != INTEGER_CST)
+ return NULL_TREE;
+ break;
+
+ default:;
+ return NULL_TREE;
+ }
+
+ /* We now have a pow or powi builtin function call with a constant
+ exponent. */
+
+ *type_out = NULL_TREE;
+
+ /* Catch squaring. */
+ if ((host_integerp (exp, 0)
+ && tree_low_cst (exp, 0) == 2)
+ || (TREE_CODE (exp) == REAL_CST
+ && REAL_VALUES_EQUAL (TREE_REAL_CST (exp), dconst2)))
+ {
+ *type_in = TREE_TYPE (base);
+ return build2 (MULT_EXPR, TREE_TYPE (base), base, base);
+ }
+
+ /* Catch square root. */
+ if (TREE_CODE (exp) == REAL_CST
+ && REAL_VALUES_EQUAL (TREE_REAL_CST (exp), dconsthalf))
+ {
+ tree newfn = mathfn_built_in (TREE_TYPE (base), BUILT_IN_SQRT);
+ *type_in = get_vectype_for_scalar_type (TREE_TYPE (base));
+ if (*type_in)
+ {
+ newfn = build_call_expr (newfn, 1, base);
+ if (vectorizable_function (newfn, *type_in, *type_in) != NULL_TREE)
+ return newfn;
+ }
+ }
+
+ return NULL_TREE;
}
tree type, half_type;
tree pattern_expr;
- if (TREE_CODE (last_stmt) != MODIFY_EXPR)
+ if (TREE_CODE (last_stmt) != GIMPLE_MODIFY_STMT)
return NULL;
- expr = TREE_OPERAND (last_stmt, 1);
+ expr = GIMPLE_STMT_OPERAND (last_stmt, 1);
type = TREE_TYPE (expr);
/* Look for the following pattern
if (!widened_name_p (oprnd0, last_stmt, &half_type, &stmt))
return NULL;
- oprnd0 = TREE_OPERAND (TREE_OPERAND (stmt, 1), 0);
+ oprnd0 = TREE_OPERAND (GIMPLE_STMT_OPERAND (stmt, 1), 0);
*type_in = half_type;
*type_out = type;
/* Check target support */
pattern_vectype = get_vectype_for_scalar_type (type_in);
+ if (!pattern_vectype)
+ return;
+
optab = optab_for_tree_code (TREE_CODE (pattern_expr), pattern_vectype);
vec_mode = TYPE_MODE (pattern_vectype);
if (!optab
var = create_tmp_var (pattern_type, "patt");
add_referenced_var (var);
var_name = make_ssa_name (var, NULL_TREE);
- pattern_expr = build2 (MODIFY_EXPR, void_type_node, var_name, pattern_expr);
+ pattern_expr = build_gimple_modify_stmt (var_name, pattern_expr);
SSA_NAME_DEF_STMT (var_name) = pattern_expr;
bsi_insert_before (&si, pattern_expr, BSI_SAME_STMT);
ann = stmt_ann (pattern_expr);