+2007-02-11 Tehila Meyzels <tehila@il.ibm.com>
+ Ira Rosen <irar@il.ibm.com>
+ Dorit Nuzman <dorit@il.ibm.com>
+
+ * doc/tm.texi (TARGET_VECTORIZE_BUILTIN_CONVERSION): New target hook.
+ * targhooks.c (default_builtin_vectorized_conversion): New.
+ * targhooks.h (default_builtin_vectorized_function): New declaration.
+ * target.h (struct vectorize): Add builtin_conversion field.
+ * tree-vectorizer.h (type_conversion_vec_info_type): New enum
+ stmt_vec_info_type value.
+ (vectorizable_conversion): New declaration.
+ * tree-vect-analyze.c (vect_analyze_operations): Add
+ vectorizable_conversion call.
+ * target-def.h (TARGET_VECTORIZE_BUILTIN_CONVERSION): New.
+ * tree-vect-transform.c (vectorizable_conversion): New function.
+ (vect_transform_stmt): Add case for type_conversion_vec_info_type.
+ * tree-vect-generic.c (expand_vector_operations_1): Consider correct
+ mode.
+ * config/rs6000/rs6000.c (rs6000_builtin_conversion): New.
+ (TARGET_VECTORIZE_BUILTIN_CONVERSION): Defined.
+ (rs6000_expand_builtin): Add handling a case of ALTIVEC_BUILTIN_VCFUX or
+ ALTIVEC_BUILTIN_VCFSX.
+
2007-02-10 John David Anglin <dave.anglin@nrc-cnrc.gc.ca>
PR target/30634
static tree rs6000_builtin_mask_for_load (void);
static tree rs6000_builtin_mul_widen_even (tree);
static tree rs6000_builtin_mul_widen_odd (tree);
+static tree rs6000_builtin_conversion (enum tree_code, tree);
static void def_builtin (int, const char *, tree, int);
static void rs6000_init_builtins (void);
#define TARGET_VECTORIZE_BUILTIN_MUL_WIDEN_EVEN rs6000_builtin_mul_widen_even
#undef TARGET_VECTORIZE_BUILTIN_MUL_WIDEN_ODD
#define TARGET_VECTORIZE_BUILTIN_MUL_WIDEN_ODD rs6000_builtin_mul_widen_odd
+#undef TARGET_VECTORIZE_BUILTIN_CONVERSION
+#define TARGET_VECTORIZE_BUILTIN_CONVERSION rs6000_builtin_conversion
#undef TARGET_INIT_BUILTINS
#define TARGET_INIT_BUILTINS rs6000_init_builtins
return 0;
}
+/* Implement targetm.vectorize.builtin_conversion. */
+static tree
+rs6000_builtin_conversion (enum tree_code code, tree type)
+{
+ if (!TARGET_ALTIVEC)
+ return NULL_TREE;
+
+ switch (code)
+ {
+ case FLOAT_EXPR:
+ switch (TYPE_MODE (type))
+ {
+ case V4SImode:
+ return TYPE_UNSIGNED (type) ?
+ rs6000_builtin_decls[ALTIVEC_BUILTIN_VCFUX] :
+ rs6000_builtin_decls[ALTIVEC_BUILTIN_VCFSX];
+ default:
+ return NULL_TREE;
+ }
+ default:
+ return NULL_TREE;
+ }
+}
+
/* Implement targetm.vectorize.builtin_mul_widen_even. */
static tree
rs6000_builtin_mul_widen_even (tree type)
return target;
}
+
+ if (fcode == ALTIVEC_BUILTIN_VCFUX
+ || fcode == ALTIVEC_BUILTIN_VCFSX)
+ {
+ if (!TREE_CHAIN (arglist))
+ {
+ tree t, arg0;
+ t = NULL_TREE;
+ t = tree_cons (NULL_TREE, integer_zero_node, t);
+ arg0 = TREE_VALUE (arglist);
+ t = tree_cons (NULL_TREE, arg0, t);
+ arglist = t;
+ TREE_OPERAND (exp, 1) = t;
+ }
+ }
if (TARGET_ALTIVEC)
{
@code{widen_mult_hi/lo} idioms will be used.
@end deftypefn
+@deftypefn {Target Hook} tree TARGET_VECTORIZE_BUILTIN_CONVERSION (enum tree_code @var{code}, tree @var{type})
+This hook should return the DECL of a function that implements conversion of the
+input vector of type @var{type}.
+If @var{type} is an integral type, the result of the conversion is a vector of
+floating-point type of the same size.
+If @var{type} is a floating-point type, the result of the conversion is a vector
+of integral type of the same size.
+@var{code} specifies how the conversion is to be applied
+(truncation, rounding, etc.).
+
+If this hook is defined, the autovectorizer will use the
+@code{TARGET_VECTORIZE_BUILTIN_CONVERSION} target hook when vectorizing
+conversion. Otherwise, it will return @code{NULL_TREE}.
+@end deftypefn
+
@deftypefn {Target Hook} tree TARGET_VECTORIZE_BUILTIN_VECTORIZED_FUNCTION (enum built_in_function @var{code}, tree @var{vec_type_out}, tree @var{vec_type_in})
This hook should return the decl of a function that implements the vectorized
variant of the builtin function with builtin function code @var{code} or
#define TARGET_VECTORIZE_BUILTIN_MASK_FOR_LOAD 0
#define TARGET_VECTORIZE_BUILTIN_VECTORIZED_FUNCTION default_builtin_vectorized_function
+#define TARGET_VECTORIZE_BUILTIN_CONVERSION default_builtin_vectorized_conversion
#define TARGET_VECTORIZE_BUILTIN_MUL_WIDEN_EVEN 0
#define TARGET_VECTORIZE_BUILTIN_MUL_WIDEN_ODD 0
{ \
TARGET_VECTORIZE_BUILTIN_MASK_FOR_LOAD, \
TARGET_VECTORIZE_BUILTIN_VECTORIZED_FUNCTION, \
+ TARGET_VECTORIZE_BUILTIN_CONVERSION, \
TARGET_VECTORIZE_BUILTIN_MUL_WIDEN_EVEN, \
TARGET_VECTORIZE_BUILTIN_MUL_WIDEN_ODD \
}
function, or NULL_TREE if not available. */
tree (* builtin_vectorized_function) (unsigned, tree, tree);
+ /* Returns a code for builtin that realizes vectorized version of
+ conversion, or NULL_TREE if not available. */
+ tree (* builtin_conversion) (unsigned, tree);
+
/* Target builtin that implements vector widening multiplication.
builtin_mul_widen_eve computes the element-by-element products
for the even elements, and builtin_mul_widen_odd computes the
return NULL_TREE;
}
+/* Vectorized conversion. */
+
+tree
+default_builtin_vectorized_conversion (enum tree_code code ATTRIBUTE_UNUSED,
+ tree type ATTRIBUTE_UNUSED)
+{
+ return NULL_TREE;
+}
+
bool
hook_bool_CUMULATIVE_ARGS_mode_tree_bool_false (
CUMULATIVE_ARGS *ca ATTRIBUTE_UNUSED,
extern tree default_builtin_vectorized_function (enum built_in_function, tree, tree);
+extern tree default_builtin_vectorized_conversion (enum tree_code, tree);
+
/* These are here, and not in hooks.[ch], because not all users of
hooks.h include tm.h, and thus we don't have CUMULATIVE_ARGS. */
+2007-02-11 Tehila Meyzels <tehila@il.ibm.com>
+ Dorit Nuzman <dorit@il.ibm.com>
+
+ * gcc.dg/vect/vect-intfloat-conversion.c-1: New test.
+ * gcc.dg/vect/vect-intfloat-conversion.c-2: New test.
+ * gcc.dg/vect/vect-93.c: Another loop gets vectorized on powerpc.
+ * gcc.dg/vect/vect-113.c: Likewise.
+
+ * gcc.dg/vect/vect-iv-11.c: A loop gets vectorized.
+
2007-02-10 Richard Henderson <rth@redhat.com>
* lib/target-supports.exp (check_effective_target_tls): Redefine
int i;
float a[N];
- /* Induction. */
+ /* Induction and type conversion. */
for ( i = 0; i < N; i++)
{
a[i] = i;
return main1 ();
}
-/* { dg-final { scan-tree-dump-times "vectorized 0 loops" 1 "vect" } } */
+/* { dg-final { scan-tree-dump-times "vectorized 1 loops" 1 "vect" { target powerpc*-*-* } } } */
/* { dg-final { cleanup-tree-dump "vect" } } */
return 0;
}
-/* in main1 */
-/* { dg-final { scan-tree-dump-times "vectorized 2 loops" 1 "vect" } } */
+/* 2 loops vectorized in main1, 2 loops vectorized in main:
+ the first loop in main requires vectorization of conversions,
+ the second loop in main requires vectorization of misaliged load: */
+
+/* main && main1 together: */
+/* { dg-final { scan-tree-dump-times "vectorized 2 loops" 2 "vect" { target powerpc*-*-* } } } */
/* { dg-final { scan-tree-dump-times "Alignment of access forced using peeling" 2 "vect" { target vect_no_align } } } */
/* { dg-final { scan-tree-dump-times "Alignment of access forced using peeling" 3 "vect" { xfail vect_no_align } } } */
-/* in main */
-/* { dg-final { scan-tree-dump-times "vectorized 1 loops" 1 "vect" { xfail vect_no_align } } } */
+/* in main1: */
+/* { dg-final { scan-tree-dump-times "vectorized 2 loops" 1 "vect" { target {! powerpc*-*-* } } } } */
+/* { dg-final { scan-tree-dump-times "vectorized 2 loops" 1 "vect" { target vect_no_align } } } */
+
+/* in main: */
+/* { dg-final { scan-tree-dump-times "vectorized 0 loops" 1 "vect" { target vect_no_align } } } */
/* { dg-final { scan-tree-dump-times "Vectorizing an unaligned access" 1 "vect" { xfail vect_no_align } } } */
+
/* { dg-final { cleanup-tree-dump "vect" } } */
return 0;
}
-/* { dg-final { scan-tree-dump-times "vectorized 1 loops" 1 "vect" { xfail *-*-* } } } */
+/* { dg-final { scan-tree-dump-times "vectorized 1 loops" 1 "vect" } } */
/* { dg-final { cleanup-tree-dump "vect" } } */
ok = (vectorizable_type_promotion (stmt, NULL, NULL)
|| vectorizable_type_demotion (stmt, NULL, NULL)
+ || vectorizable_conversion (stmt, NULL, NULL)
|| vectorizable_operation (stmt, NULL, NULL)
|| vectorizable_assignment (stmt, NULL, NULL)
|| vectorizable_load (stmt, NULL, NULL)
&& TREE_CODE_CLASS (code) != tcc_binary)
return;
- if (code == NOP_EXPR || code == VIEW_CONVERT_EXPR)
+ if (code == NOP_EXPR
+ || code == FLOAT_EXPR
+ || code == FIX_TRUNC_EXPR
+ || code == VIEW_CONVERT_EXPR)
return;
gcc_assert (code != CONVERT_EXPR);
}
+/* Function vectorizable_conversion.
+
+Check if STMT performs a conversion operation, that can be vectorized.
+If VEC_STMT is also passed, vectorize the STMT: create a vectorized
+stmt to replace it, put it in VEC_STMT, and insert it at BSI.
+Return FALSE if not a vectorizable STMT, TRUE otherwise. */
+
+bool
+vectorizable_conversion (tree stmt, block_stmt_iterator * bsi,
+ tree * vec_stmt)
+{
+ tree vec_dest;
+ tree scalar_dest;
+ tree operation;
+ tree op0;
+ tree vec_oprnd0 = NULL_TREE;
+ stmt_vec_info stmt_info = vinfo_for_stmt (stmt);
+ loop_vec_info loop_vinfo = STMT_VINFO_LOOP_VINFO (stmt_info);
+ enum tree_code code;
+ tree new_temp;
+ tree def, def_stmt;
+ enum vect_def_type dt0;
+ tree new_stmt;
+ int nunits_in;
+ int nunits_out;
+ int ncopies, j;
+ tree vectype_out, vectype_in;
+ tree rhs_type, lhs_type;
+ tree builtin_decl, params;
+ stmt_vec_info prev_stmt_info;
+
+ /* Is STMT a vectorizable conversion? */
+
+ if (!STMT_VINFO_RELEVANT_P (stmt_info))
+ return false;
+
+ gcc_assert (STMT_VINFO_DEF_TYPE (stmt_info) == vect_loop_def);
+
+ if (STMT_VINFO_LIVE_P (stmt_info))
+ {
+ /* FORNOW: not yet supported. */
+ if (vect_print_dump_info (REPORT_DETAILS))
+ fprintf (vect_dump, "value used after loop.");
+ return false;
+ }
+
+ if (TREE_CODE (stmt) != GIMPLE_MODIFY_STMT)
+ return false;
+
+ if (TREE_CODE (GIMPLE_STMT_OPERAND (stmt, 0)) != SSA_NAME)
+ return false;
+
+ operation = GIMPLE_STMT_OPERAND (stmt, 1);
+ code = TREE_CODE (operation);
+ if (code != FIX_TRUNC_EXPR && code != FLOAT_EXPR)
+ return false;
+
+ /* Check types of lhs and rhs */
+ op0 = TREE_OPERAND (operation, 0);
+ rhs_type = TREE_TYPE (op0);
+ vectype_in = get_vectype_for_scalar_type (rhs_type);
+ nunits_in = TYPE_VECTOR_SUBPARTS (vectype_in);
+
+ scalar_dest = GIMPLE_STMT_OPERAND (stmt, 0);
+ lhs_type = TREE_TYPE (scalar_dest);
+ vectype_out = get_vectype_for_scalar_type (lhs_type);
+ gcc_assert (STMT_VINFO_VECTYPE (stmt_info) == vectype_out);
+ nunits_out = TYPE_VECTOR_SUBPARTS (vectype_out);
+
+ /* FORNOW: need to extend to support short<->float conversions as well. */
+ if (nunits_out != nunits_in)
+ return false;
+
+ /* Bail out if the types are both integral or non-integral */
+ if ((INTEGRAL_TYPE_P (rhs_type) && INTEGRAL_TYPE_P (lhs_type))
+ || (!INTEGRAL_TYPE_P (rhs_type) && !INTEGRAL_TYPE_P (lhs_type)))
+ return false;
+
+ /* Sanity check: make sure that at least one copy of the vectorized stmt
+ needs to be generated. */
+ ncopies = LOOP_VINFO_VECT_FACTOR (loop_vinfo) / nunits_in;
+ gcc_assert (ncopies >= 1);
+
+ if (!vect_is_simple_use (op0, loop_vinfo, &def_stmt, &def, &dt0))
+ {
+ if (vect_print_dump_info (REPORT_DETAILS))
+ fprintf (vect_dump, "use not simple.");
+ return false;
+ }
+
+ /* Supportable by target? */
+ if (!targetm.vectorize.builtin_conversion (code, vectype_in))
+ {
+ if (vect_print_dump_info (REPORT_DETAILS))
+ fprintf (vect_dump, "op not supported by target.");
+ return false;
+ }
+
+ if (!vec_stmt) /* transformation not required. */
+ {
+ STMT_VINFO_TYPE (stmt_info) = type_conversion_vec_info_type;
+ return true;
+ }
+
+ /** Transform. **/
+
+ if (vect_print_dump_info (REPORT_DETAILS))
+ fprintf (vect_dump, "transform conversion.");
+
+ /* Handle def. */
+ vec_dest = vect_create_destination_var (scalar_dest, vectype_out);
+
+ prev_stmt_info = NULL;
+ for (j = 0; j < ncopies; j++)
+ {
+ tree sym;
+ ssa_op_iter iter;
+
+ if (j == 0)
+ vec_oprnd0 = vect_get_vec_def_for_operand (op0, stmt, NULL);
+ else
+ vec_oprnd0 = vect_get_vec_def_for_stmt_copy (dt0, vec_oprnd0);
+ params = build_tree_list (NULL_TREE, vec_oprnd0);
+
+ builtin_decl =
+ targetm.vectorize.builtin_conversion (code, vectype_in);
+ new_stmt = build_function_call_expr (builtin_decl, params);
+
+ /* Arguments are ready. create the new vector stmt. */
+ new_stmt = build2 (GIMPLE_MODIFY_STMT, void_type_node, vec_dest,
+ new_stmt);
+ new_temp = make_ssa_name (vec_dest, new_stmt);
+ GIMPLE_STMT_OPERAND (new_stmt, 0) = new_temp;
+ vect_finish_stmt_generation (stmt, new_stmt, bsi);
+ FOR_EACH_SSA_TREE_OPERAND (sym, new_stmt, iter, SSA_OP_ALL_VIRTUALS)
+ {
+ if (TREE_CODE (sym) == SSA_NAME)
+ sym = SSA_NAME_VAR (sym);
+ mark_sym_for_renaming (sym);
+ }
+
+ if (j == 0)
+ STMT_VINFO_VEC_STMT (stmt_info) = *vec_stmt = new_stmt;
+ else
+ STMT_VINFO_RELATED_STMT (prev_stmt_info) = new_stmt;
+ prev_stmt_info = vinfo_for_stmt (new_stmt);
+ }
+ return true;
+}
+
+
/* Function vectorizable_assignment.
Check if STMT performs an assignment (copy) that can be vectorized.
gcc_assert (done);
break;
+ case type_conversion_vec_info_type:
+ done = vectorizable_conversion (stmt, bsi, &vec_stmt);
+ gcc_assert (done);
+ break;
+
case op_vec_info_type:
done = vectorizable_operation (stmt, bsi, &vec_stmt);
gcc_assert (done);
condition_vec_info_type,
reduc_vec_info_type,
type_promotion_vec_info_type,
- type_demotion_vec_info_type
+ type_demotion_vec_info_type,
+ type_conversion_vec_info_type
};
/* Indicates whether/how a variable is used in the loop. */
extern bool vectorizable_operation (tree, block_stmt_iterator *, tree *);
extern bool vectorizable_type_promotion (tree, block_stmt_iterator *, tree *);
extern bool vectorizable_type_demotion (tree, block_stmt_iterator *, tree *);
+extern bool vectorizable_conversion (tree, block_stmt_iterator *,
+ tree *);
extern bool vectorizable_assignment (tree, block_stmt_iterator *, tree *);
extern tree vectorizable_function (tree, tree, tree);
extern bool vectorizable_call (tree, block_stmt_iterator *, tree *);