From 22c2f6bdda9682df91ef7761d4b77c01e8bbcd37 Mon Sep 17 00:00:00 2001 From: rguenth Date: Mon, 27 Nov 2006 12:41:51 +0000 Subject: [PATCH] 2006-11-27 Richard Guenther Zdenek Dvorak * target.h (struct gcc_target): Add builtin_vectorized_function target hook. * target-def.h (TARGET_VECTORIZE): Likewise. * doc/tm.texi (TARGET_VECTORIZE_BUILTIN_VECTORIZED_FUNCTION): Document new target hook. * targhooks.h (default_builtin_vectorized_function): Declare. * targhooks.c (default_builtin_vectorized_function): Define. * tree-vectorizer.h (stmt_vec_info_type): Add call_vec_info_type. (vectorizable_call): Declare. * tree-vect-analyze.c (vect_analyze_operations): Call vectorizable_call. * tree-vect-transform.c (vectorizable_function): New static function. (build_vectorized_function_call): Likewise. (vectorizable_call): New function. (vect_transform_stmt): Handle vectorizable calls. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@119249 138bc75d-0d04-0410-961f-82ee72b054a4 --- gcc/ChangeLog | 19 ++++++ gcc/doc/tm.texi | 7 +++ gcc/target-def.h | 10 +++- gcc/target.h | 4 ++ gcc/targhooks.c | 9 +++ gcc/targhooks.h | 2 + gcc/tree-vect-analyze.c | 1 + gcc/tree-vect-transform.c | 150 ++++++++++++++++++++++++++++++++++++++++++++++ gcc/tree-vectorizer.h | 2 + 9 files changed, 201 insertions(+), 3 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 65451c7..4d4a97d 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,4 +1,23 @@ 2006-11-27 Richard Guenther + Zdenek Dvorak + + * target.h (struct gcc_target): Add builtin_vectorized_function + target hook. + * target-def.h (TARGET_VECTORIZE): Likewise. + * doc/tm.texi (TARGET_VECTORIZE_BUILTIN_VECTORIZED_FUNCTION): + Document new target hook. + * targhooks.h (default_builtin_vectorized_function): Declare. + * targhooks.c (default_builtin_vectorized_function): Define. + * tree-vectorizer.h (stmt_vec_info_type): Add call_vec_info_type. + (vectorizable_call): Declare. + * tree-vect-analyze.c (vect_analyze_operations): Call + vectorizable_call. + * tree-vect-transform.c (vectorizable_function): New static function. + (build_vectorized_function_call): Likewise. + (vectorizable_call): New function. + (vect_transform_stmt): Handle vectorizable calls. + +2006-11-27 Richard Guenther PR middle-end/25620 * builtins.c (expand_builtin_pow): Optimize non integer valued diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi index 768c7c7..70e30ae 100644 --- a/gcc/doc/tm.texi +++ b/gcc/doc/tm.texi @@ -5306,6 +5306,13 @@ preserved (e.g. used only by a reduction computation). Otherwise, the @code{widen_mult_hi/lo} idioms will be used. @end deftypefn +@deftypefn {Target Hook} tree TARGET_VECTORIZE_BUILTIN_VECTORIZED_FUNCTION (enum built_in_function @var{code}, tree @var{vec_type}) +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 +@code{NULL_TREE} if such a function is not available. The return type of +the vectorized function shall be of vector type @var{vec_type}. +@end deftypefn + @node Anchored Addresses @section Anchored Addresses @cindex anchored addresses diff --git a/gcc/target-def.h b/gcc/target-def.h index 1e158c1..580c327 100644 --- a/gcc/target-def.h +++ b/gcc/target-def.h @@ -332,13 +332,17 @@ Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. TARGET_SCHED_SET_SCHED_FLAGS} #define TARGET_VECTORIZE_BUILTIN_MASK_FOR_LOAD 0 +#define TARGET_VECTORIZE_BUILTIN_VECTORIZED_FUNCTION default_builtin_vectorized_function #define TARGET_VECTORIZE_BUILTIN_MUL_WIDEN_EVEN 0 #define TARGET_VECTORIZE_BUILTIN_MUL_WIDEN_ODD 0 #define TARGET_VECTORIZE \ - {TARGET_VECTORIZE_BUILTIN_MASK_FOR_LOAD, \ - TARGET_VECTORIZE_BUILTIN_MUL_WIDEN_EVEN, \ - TARGET_VECTORIZE_BUILTIN_MUL_WIDEN_ODD} + { \ + TARGET_VECTORIZE_BUILTIN_MASK_FOR_LOAD, \ + TARGET_VECTORIZE_BUILTIN_VECTORIZED_FUNCTION, \ + TARGET_VECTORIZE_BUILTIN_MUL_WIDEN_EVEN, \ + TARGET_VECTORIZE_BUILTIN_MUL_WIDEN_ODD \ + } #define TARGET_DEFAULT_TARGET_FLAGS 0 diff --git a/gcc/target.h b/gcc/target.h index 82eaccd..1147142 100644 --- a/gcc/target.h +++ b/gcc/target.h @@ -370,6 +370,10 @@ struct gcc_target function. */ tree (* builtin_mask_for_load) (void); + /* Returns a code for builtin that realizes vectorized version of + function, or NULL_TREE if not available. */ + tree (* builtin_vectorized_function) (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 diff --git a/gcc/targhooks.c b/gcc/targhooks.c index a12d6b5..e7bdf0b 100644 --- a/gcc/targhooks.c +++ b/gcc/targhooks.c @@ -319,6 +319,15 @@ default_invalid_within_doloop (rtx insn) return NULL; } +/* Mapping of builtin functions to vectorized variants. */ + +tree +default_builtin_vectorized_function (enum built_in_function fn ATTRIBUTE_UNUSED, + tree type ATTRIBUTE_UNUSED) +{ + return NULL_TREE; +} + bool hook_bool_CUMULATIVE_ARGS_mode_tree_bool_false ( CUMULATIVE_ARGS *ca ATTRIBUTE_UNUSED, diff --git a/gcc/targhooks.h b/gcc/targhooks.h index f6d50dd..5f63dd7 100644 --- a/gcc/targhooks.h +++ b/gcc/targhooks.h @@ -57,6 +57,8 @@ extern const char * default_invalid_within_doloop (rtx); extern bool default_narrow_bitfield (void); +extern tree default_builtin_vectorized_function (enum built_in_function, 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. */ diff --git a/gcc/tree-vect-analyze.c b/gcc/tree-vect-analyze.c index 4ea7b15..a0d6e087 100644 --- a/gcc/tree-vect-analyze.c +++ b/gcc/tree-vect-analyze.c @@ -301,6 +301,7 @@ vect_analyze_operations (loop_vec_info loop_vinfo) || vectorizable_operation (stmt, NULL, NULL) || vectorizable_assignment (stmt, NULL, NULL) || vectorizable_load (stmt, NULL, NULL) + || vectorizable_call (stmt, NULL, NULL) || vectorizable_store (stmt, NULL, NULL) || vectorizable_condition (stmt, NULL, NULL)); diff --git a/gcc/tree-vect-transform.c b/gcc/tree-vect-transform.c index b2771bb..84ae19f 100644 --- a/gcc/tree-vect-transform.c +++ b/gcc/tree-vect-transform.c @@ -1566,6 +1566,152 @@ vectorizable_reduction (tree stmt, block_stmt_iterator *bsi, tree *vec_stmt) return true; } +/* Checks if CALL can be vectorized in type VECTYPE. Returns + true if the target has a vectorized version of the function, + or false if the function cannot be vectorized. */ + +static bool +vectorizable_function (tree call, tree vectype) +{ + tree fndecl = get_callee_fndecl (call); + + /* We only handle functions that do not read or clobber memory -- i.e. + const or novops ones. */ + if (!(call_expr_flags (call) & (ECF_CONST | ECF_NOVOPS))) + return false; + + if (!fndecl + || TREE_CODE (fndecl) != FUNCTION_DECL + || !DECL_BUILT_IN (fndecl)) + return false; + + if (targetm.vectorize.builtin_vectorized_function (DECL_FUNCTION_CODE (fndecl), vectype)) + return true; + + return false; +} + +/* Returns an expression that performs a call to vectorized version + of FNDECL in type VECTYPE, with the arguments given by ARGS. + If extra statements need to be generated, they are inserted + before BSI. */ + +static tree +build_vectorized_function_call (tree fndecl, + tree vectype, tree args) +{ + tree vfndecl; + enum built_in_function code = DECL_FUNCTION_CODE (fndecl); + + /* The target specific builtin should be available. */ + vfndecl = targetm.vectorize.builtin_vectorized_function (code, vectype); + gcc_assert (vfndecl != NULL_TREE); + + return build_function_call_expr (vfndecl, args); +} + +/* Function vectorizable_call. + + Check if STMT performs a function call 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_call (tree stmt, block_stmt_iterator *bsi, tree *vec_stmt) +{ + tree vec_dest; + tree scalar_dest; + tree operation; + tree op, args, type; + tree vec_oprnd, vargs, *pvargs_end; + stmt_vec_info stmt_info = vinfo_for_stmt (stmt); + tree vectype = STMT_VINFO_VECTYPE (stmt_info); + loop_vec_info loop_vinfo = STMT_VINFO_LOOP_VINFO (stmt_info); + tree fndecl, rhs, new_temp, def, def_stmt; + enum vect_def_type dt; + + /* Is STMT a vectorizable call? */ + 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 (TREE_CODE (operation) != CALL_EXPR) + return false; + + /* For now, we only vectorize functions if a target specific builtin + is available. TODO -- in some cases, it might be profitable to + insert the calls for pieces of the vector, in order to be able + to vectorize other operations in the loop. */ + if (!vectorizable_function (operation, vectype)) + { + if (vect_print_dump_info (REPORT_DETAILS)) + fprintf (vect_dump, "function is not vectorizable."); + + return false; + } + gcc_assert (!stmt_references_memory_p (stmt)); + + for (args = TREE_OPERAND (operation, 1); args; args = TREE_CHAIN (args)) + { + op = TREE_VALUE (args); + + if (!vect_is_simple_use (op, loop_vinfo, &def_stmt, &def, &dt)) + { + if (vect_print_dump_info (REPORT_DETAILS)) + fprintf (vect_dump, "use not simple."); + return false; + } + } + + if (!vec_stmt) /* transformation not required. */ + { + STMT_VINFO_TYPE (stmt_info) = call_vec_info_type; + return true; + } + + /** Transform. **/ + + if (vect_print_dump_info (REPORT_DETAILS)) + fprintf (vect_dump, "transform operation."); + + /* Handle def. */ + scalar_dest = TREE_OPERAND (stmt, 0); + vec_dest = vect_create_destination_var (scalar_dest, vectype); + + /* Handle uses. */ + vargs = NULL_TREE; + pvargs_end = &vargs; + for (args = TREE_OPERAND (operation, 1); args; args = TREE_CHAIN (args)) + { + op = TREE_VALUE (args); + vec_oprnd = vect_get_vec_def_for_operand (op, stmt, NULL); + + *pvargs_end = tree_cons (NULL_TREE, vec_oprnd, NULL_TREE); + pvargs_end = &TREE_CHAIN (*pvargs_end); + } + + fndecl = get_callee_fndecl (operation); + rhs = build_vectorized_function_call (fndecl, vectype, vargs); + *vec_stmt = build2 (MODIFY_EXPR, vectype, vec_dest, rhs); + new_temp = make_ssa_name (vec_dest, *vec_stmt); + TREE_OPERAND (*vec_stmt, 0) = new_temp; + + vect_finish_stmt_generation (stmt, *vec_stmt, bsi); + + /* The call in STMT might prevent it from being removed in dce. We however + cannot remove it here, due to the way the ssa name it defines is mapped + to the new definition. So just replace rhs of the statement with something + harmless. */ + type = TREE_TYPE (scalar_dest); + TREE_OPERAND (stmt, 1) = fold_convert (type, integer_zero_node); + + return true; +} + /* Function vectorizable_assignment. @@ -3721,6 +3867,10 @@ vect_transform_stmt (tree stmt, block_stmt_iterator *bsi, bool *strided_store) gcc_assert (done); break; + case call_vec_info_type: + done = vectorizable_call (stmt, bsi, &vec_stmt); + break; + default: if (vect_print_dump_info (REPORT_DETAILS)) fprintf (vect_dump, "stmt not supported."); diff --git a/gcc/tree-vectorizer.h b/gcc/tree-vectorizer.h index d60a494..6af68a3 100644 --- a/gcc/tree-vectorizer.h +++ b/gcc/tree-vectorizer.h @@ -163,6 +163,7 @@ enum stmt_vec_info_type { load_vec_info_type, store_vec_info_type, op_vec_info_type, + call_vec_info_type, assignment_vec_info_type, condition_vec_info_type, reduc_vec_info_type, @@ -397,6 +398,7 @@ 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_assignment (tree, block_stmt_iterator *, tree *); +extern bool vectorizable_call (tree, block_stmt_iterator *, tree *); extern bool vectorizable_condition (tree, block_stmt_iterator *, tree *); extern bool vectorizable_live_operation (tree, block_stmt_iterator *, tree *); extern bool vectorizable_reduction (tree, block_stmt_iterator *, tree *); -- 2.7.4