summaryrefslogtreecommitdiff
path: root/gcc/tree-vectorizer.c
diff options
context:
space:
mode:
authorirar <irar@138bc75d-0d04-0410-961f-82ee72b054a4>2008-08-12 06:31:57 +0000
committerirar <irar@138bc75d-0d04-0410-961f-82ee72b054a4>2008-08-12 06:31:57 +0000
commit52394a67eed91a2b0f71962d217053755ca17aca (patch)
treed08aa3cd7532e377a8e591040da5b32f9ae3e84b /gcc/tree-vectorizer.c
parent73646cd96cff4e4e29f2373cabae387e712fc765 (diff)
downloadgcc-52394a67eed91a2b0f71962d217053755ca17aca.tar.gz
* tree-vectorizer.c: Depend on langhooks.h.
(supportable_widening_operation): Add two arguments. Support double type conversions. (supportable_narrowing_operation): Likewise. * tree-vectorizer.h (supportable_widening_operation): Add two arguments. (supportable_narrowing_operation): Likewise. * tree-vect-patterns.c (vect_recog_widen_mult_pattern) : Call supportable_widening_operation with correct arguments. * tree-vect-transform.c (vectorizable_conversion): Likewise. (vectorizable_type_demotion): Support double type conversions. (vectorizable_type_promotion): Likewise. * Makefile.in (tree-vectorizer.o): Depend on langhooks.h. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@138988 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/tree-vectorizer.c')
-rw-r--r--gcc/tree-vectorizer.c98
1 files changed, 88 insertions, 10 deletions
diff --git a/gcc/tree-vectorizer.c b/gcc/tree-vectorizer.c
index 22e2e0c4cee..78f82624c23 100644
--- a/gcc/tree-vectorizer.c
+++ b/gcc/tree-vectorizer.c
@@ -147,6 +147,7 @@ along with GCC; see the file COPYING3. If not see
#include "hashtab.h"
#include "tree-vectorizer.h"
#include "tree-pass.h"
+#include "langhooks.h"
/*************************************************************************
General Vectorization Utilities
@@ -2136,12 +2137,17 @@ vect_is_simple_use (tree operand, loop_vec_info loop_vinfo, gimple *def_stmt,
vectorizing the operation, if available.
- DECL1 and DECL2 are decls of target builtin functions to be used
when vectorizing the operation, if available. In this case,
- CODE1 and CODE2 are CALL_EXPR. */
+ CODE1 and CODE2 are CALL_EXPR.
+ - DOUBLE_OP determines if the operation is a double cast, like
+ char->short->int
+ - INTERM_TYPE is the intermediate type required to perform the
+ widening operation (short in the above example) */
bool
supportable_widening_operation (enum tree_code code, gimple stmt, tree vectype,
tree *decl1, tree *decl2,
- enum tree_code *code1, enum tree_code *code2)
+ enum tree_code *code1, enum tree_code *code2,
+ bool *double_op, tree *interm_type)
{
stmt_vec_info stmt_info = vinfo_for_stmt (stmt);
loop_vec_info loop_info = STMT_VINFO_LOOP_VINFO (stmt_info);
@@ -2154,6 +2160,8 @@ supportable_widening_operation (enum tree_code code, gimple stmt, tree vectype,
tree wide_vectype = get_vectype_for_scalar_type (type);
enum tree_code c1, c2;
+ *double_op = false;
+
/* The result of a vectorized widening operation usually requires two vectors
(because the widened results do not fit int one vector). The generated
vector results would normally be expected to be generated in the same
@@ -2264,12 +2272,57 @@ supportable_widening_operation (enum tree_code code, gimple stmt, tree vectype,
vec_mode = TYPE_MODE (vectype);
if ((icode1 = optab_handler (optab1, vec_mode)->insn_code) == CODE_FOR_nothing
- || insn_data[icode1].operand[0].mode != TYPE_MODE (wide_vectype)
|| (icode2 = optab_handler (optab2, vec_mode)->insn_code)
- == CODE_FOR_nothing
- || insn_data[icode2].operand[0].mode != TYPE_MODE (wide_vectype))
+ == CODE_FOR_nothing)
return false;
+ /* Check if it's a double cast, like char->int. In such case the intermediate
+ type is short, and we check that char->short->int operaion is supported by
+ the target. */
+ if (insn_data[icode1].operand[0].mode != TYPE_MODE (wide_vectype)
+ || insn_data[icode2].operand[0].mode != TYPE_MODE (wide_vectype))
+ {
+ if (code == NOP_EXPR)
+ {
+ enum machine_mode intermediate_mode =
+ insn_data[icode1].operand[0].mode;
+ tree intermediate_type =
+ lang_hooks.types.type_for_mode (intermediate_mode,
+ TYPE_UNSIGNED (vectype));
+ optab optab3 = optab_for_tree_code (c1, intermediate_type,
+ optab_default);
+ optab optab4 = optab_for_tree_code (c2, intermediate_type,
+ optab_default);
+
+ if (!optab3 || !optab4)
+ return false;
+
+ if ((icode1 = optab1->handlers[(int) vec_mode].insn_code)
+ == CODE_FOR_nothing
+ || insn_data[icode1].operand[0].mode != intermediate_mode
+ || (icode2 = optab2->handlers[(int) vec_mode].insn_code)
+ == CODE_FOR_nothing
+ || insn_data[icode2].operand[0].mode != intermediate_mode
+ || (icode1 = optab3->handlers[(int) intermediate_mode].insn_code)
+ == CODE_FOR_nothing
+ || insn_data[icode1].operand[0].mode != TYPE_MODE (wide_vectype)
+ || (icode2 = optab4->handlers[(int) intermediate_mode].insn_code)
+ == CODE_FOR_nothing
+ || insn_data[icode2].operand[0].mode != TYPE_MODE (wide_vectype))
+ return false;
+ else
+ {
+ *double_op = true;
+ *interm_type = intermediate_type;
+ *code1 = c1;
+ *code2 = c2;
+ return true;
+ }
+ }
+
+ return false;
+ }
+
*code1 = c1;
*code2 = c2;
return true;
@@ -2288,16 +2341,21 @@ supportable_widening_operation (enum tree_code code, gimple stmt, tree vectype,
Output:
- CODE1 is the code of a vector operation to be used when
- vectorizing the operation, if available. */
+ vectorizing the operation, if available.
+ - DOUBLE_OP determines if the operation is a double cast, like
+ int->short->char
+ - INTERMIDIATE_TYPE is the intermediate type required to perform the
+ widening operation (short in the above example) */
bool
supportable_narrowing_operation (enum tree_code code,
const_gimple stmt, const_tree vectype,
- enum tree_code *code1)
+ enum tree_code *code1, bool *double_op,
+ tree *intermediate_type)
{
enum machine_mode vec_mode;
enum insn_code icode1;
- optab optab1;
+ optab optab1, interm_optab;
tree type = gimple_expr_type (stmt);
tree narrow_vectype = get_vectype_for_scalar_type (type);
enum tree_code c1;
@@ -2331,10 +2389,30 @@ supportable_narrowing_operation (enum tree_code code,
return false;
vec_mode = TYPE_MODE (vectype);
- if ((icode1 = optab_handler (optab1, vec_mode)->insn_code) == CODE_FOR_nothing
- || insn_data[icode1].operand[0].mode != TYPE_MODE (narrow_vectype))
+ if ((icode1 = optab_handler (optab1, vec_mode)->insn_code)
+ == CODE_FOR_nothing)
return false;
+ /* In case of NUNITS_IN == NUNITS_OUT/4 check that the it is possible to
+ perform the operation using an intermediate type of NUNITS_OUT/2. */
+ if (insn_data[icode1].operand[0].mode != TYPE_MODE (narrow_vectype))
+ {
+ enum machine_mode intermediate_mode = insn_data[icode1].operand[0].mode;
+ *intermediate_type = lang_hooks.types.type_for_mode (intermediate_mode,
+ TYPE_UNSIGNED (vectype));
+ interm_optab = optab_for_tree_code (VEC_PACK_TRUNC_EXPR,
+ *intermediate_type, optab_default);
+ if (!interm_optab)
+ return false;
+
+ if ((icode1 = interm_optab->handlers[(int) intermediate_mode].insn_code)
+ == CODE_FOR_nothing
+ || insn_data[icode1].operand[0].mode != TYPE_MODE (narrow_vectype))
+ return false;
+
+ *double_op = true;
+ }
+
*code1 = c1;
return true;
}