+ gimple def_stmt0, def_stmt1;
+ tree oprnd0, oprnd1;
+ tree type, half_type0, half_type1;
+ gimple pattern_stmt;
+ tree vectype, vectype_out;
+ tree dummy;
+ tree var;
+ enum tree_code dummy_code;
+ int dummy_int;
+ VEC (tree, heap) *dummy_vec;
+
+ if (!is_gimple_assign (last_stmt))
+ return NULL;
+
+ type = gimple_expr_type (last_stmt);
+
+ /* Starting from LAST_STMT, follow the defs of its uses in search
+ of the above pattern. */
+
+ if (gimple_assign_rhs_code (last_stmt) != MULT_EXPR)
+ return NULL;
+
+ oprnd0 = gimple_assign_rhs1 (last_stmt);
+ oprnd1 = gimple_assign_rhs2 (last_stmt);
+ if (!types_compatible_p (TREE_TYPE (oprnd0), type)
+ || !types_compatible_p (TREE_TYPE (oprnd1), type))
+ return NULL;
+
+ /* Check argument 0 */
+ if (!widened_name_p (oprnd0, last_stmt, &half_type0, &def_stmt0))
+ return NULL;
+ oprnd0 = gimple_assign_rhs1 (def_stmt0);
+
+ /* Check argument 1 */
+ if (!widened_name_p (oprnd1, last_stmt, &half_type1, &def_stmt1))
+ return NULL;
+ oprnd1 = gimple_assign_rhs1 (def_stmt1);
+
+ if (!types_compatible_p (half_type0, 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);
+ vectype_out = get_vectype_for_scalar_type (type);
+ if (!vectype
+ || !supportable_widening_operation (WIDEN_MULT_EXPR, last_stmt,
+ vectype_out, vectype,
+ &dummy, &dummy, &dummy_code,
+ &dummy_code, &dummy_int, &dummy_vec))
+ return NULL;
+
+ *type_in = vectype;
+ *type_out = vectype_out;
+
+ /* Pattern supported. Create a stmt to be used to replace the pattern: */
+ var = vect_recog_temp_ssa_var (type, NULL);
+ pattern_stmt = gimple_build_assign_with_ops (WIDEN_MULT_EXPR, var, oprnd0,
+ oprnd1);
+ SSA_NAME_DEF_STMT (var) = pattern_stmt;
+
+ if (vect_print_dump_info (REPORT_DETAILS))
+ print_gimple_stmt (vect_dump, pattern_stmt, 0, TDF_SLIM);
+
+ return pattern_stmt;
+}
+
+
+/* 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 * x
+ or
+ x = sqrt (x)
+*/
+
+static gimple
+vect_recog_pow_pattern (gimple last_stmt, tree *type_in, tree *type_out)
+{
+ tree fn, base, exp = NULL;
+ gimple stmt;
+ tree var;
+
+ if (!is_gimple_call (last_stmt) || gimple_call_lhs (last_stmt) == NULL)
+ return NULL;
+
+ fn = gimple_call_fndecl (last_stmt);
+ switch (DECL_FUNCTION_CODE (fn))
+ {
+ case BUILT_IN_POWIF:
+ case BUILT_IN_POWI:
+ case BUILT_IN_POWF:
+ case BUILT_IN_POW:
+ base = gimple_call_arg (last_stmt, 0);
+ exp = gimple_call_arg (last_stmt, 1);
+ if (TREE_CODE (exp) != REAL_CST
+ && TREE_CODE (exp) != INTEGER_CST)
+ return NULL;
+ break;
+
+ default:
+ return NULL;
+ }
+
+ /* 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);
+
+ var = vect_recog_temp_ssa_var (TREE_TYPE (base), NULL);
+ stmt = gimple_build_assign_with_ops (MULT_EXPR, var, base, base);
+ SSA_NAME_DEF_STMT (var) = stmt;
+ return stmt;
+ }
+
+ /* 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)
+ {
+ gimple stmt = gimple_build_call (newfn, 1, base);
+ if (vectorizable_function (stmt, *type_in, *type_in)
+ != NULL_TREE)
+ {
+ var = vect_recog_temp_ssa_var (TREE_TYPE (base), stmt);
+ gimple_call_set_lhs (stmt, var);
+ return stmt;
+ }
+ }
+ }
+