From 84557284812ca26206c4dcf03506db4c2ade4348 Mon Sep 17 00:00:00 2001 From: jakub Date: Thu, 6 Oct 2011 17:49:36 +0000 Subject: [PATCH] PR tree-optimization/50596 * tree-vectorizer.h (vect_is_simple_cond): New prototype. (NUM_PATTERNS): Change to 6. * tree-vect-patterns.c (vect_recog_mixed_size_cond_pattern): New function. (vect_vect_recog_func_ptrs): Add vect_recog_mixed_size_cond_pattern. (vect_mark_pattern_stmts): Don't create stmt_vinfo for def_stmt if it already has one, and don't set STMT_VINFO_VECTYPE in it if it is already set. * tree-vect-stmts.c (vect_mark_stmts_to_be_vectorized): Handle COND_EXPR in pattern stmts. (vect_is_simple_cond): No longer static. * lib/target-supports.exp (check_effective_target_vect_cond_mixed): New. * gcc.dg/vect/vect-cond-8.c: New test. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@179626 138bc75d-0d04-0410-961f-82ee72b054a4 --- gcc/ChangeLog | 15 ++++ gcc/testsuite/ChangeLog | 7 ++ gcc/testsuite/gcc.dg/vect/vect-cond-8.c | 122 +++++++++++++++++++++++++++++ gcc/testsuite/lib/target-supports.exp | 20 +++++ gcc/tree-vect-patterns.c | 131 ++++++++++++++++++++++++++++++-- gcc/tree-vect-stmts.c | 22 +++++- gcc/tree-vectorizer.h | 5 +- 7 files changed, 312 insertions(+), 10 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/vect/vect-cond-8.c diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 19516c0..a8cc833 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,18 @@ +2011-10-06 Jakub Jelinek + + PR tree-optimization/50596 + * tree-vectorizer.h (vect_is_simple_cond): New prototype. + (NUM_PATTERNS): Change to 6. + * tree-vect-patterns.c (vect_recog_mixed_size_cond_pattern): New + function. + (vect_vect_recog_func_ptrs): Add vect_recog_mixed_size_cond_pattern. + (vect_mark_pattern_stmts): Don't create stmt_vinfo for def_stmt + if it already has one, and don't set STMT_VINFO_VECTYPE in it + if it is already set. + * tree-vect-stmts.c (vect_mark_stmts_to_be_vectorized): Handle + COND_EXPR in pattern stmts. + (vect_is_simple_cond): No longer static. + 2001-10-06 Richard Henderson * config/i386/i386.c (ix86_expand_vshuffle): Add AVX2 support. diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 4adb775..ccd5187 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,10 @@ +2011-10-06 Jakub Jelinek + + PR tree-optimization/50596 + * lib/target-supports.exp (check_effective_target_vect_cond_mixed): + New. + * gcc.dg/vect/vect-cond-8.c: New test. + 2011-10-06 Richard Henderson * gcc.c-torture/execute/vect-shuffle-1.c: Remove. diff --git a/gcc/testsuite/gcc.dg/vect/vect-cond-8.c b/gcc/testsuite/gcc.dg/vect/vect-cond-8.c new file mode 100644 index 0000000..e5702c2 --- /dev/null +++ b/gcc/testsuite/gcc.dg/vect/vect-cond-8.c @@ -0,0 +1,122 @@ +/* { dg-require-effective-target vect_cond_mixed } */ + +#include "tree-vect.h" + +#define N 1024 +float a[N], b[N], c[N]; +int d[N], e[N], f[N]; +unsigned char k[N]; + +__attribute__((noinline, noclone)) void +f1 (void) +{ + int i; + for (i = 0; i < N; ++i) + k[i] = a[i] < b[i] ? 17 : 0; +} + +__attribute__((noinline, noclone)) void +f2 (void) +{ + int i; + for (i = 0; i < N; ++i) + k[i] = a[i] < b[i] ? 0 : 24; +} + +__attribute__((noinline, noclone)) void +f3 (void) +{ + int i; + for (i = 0; i < N; ++i) + k[i] = a[i] < b[i] ? 51 : 12; +} + +__attribute__((noinline, noclone)) void +f4 (void) +{ + int i; + for (i = 0; i < N; ++i) + { + int d2 = d[i], e2 = e[i]; + f[i] = a[i] < b[i] ? d2 : e2; + } +} + +__attribute__((noinline, noclone)) void +f5 (void) +{ + int i; + for (i = 0; i < N; ++i) + { + float a2 = a[i], b2 = b[i]; + c[i] = d[i] < e[i] ? a2 : b2; + } +} + +int +main () +{ + int i; + + check_vect (); + + for (i = 0; i < N; i++) + { + switch (i % 9) + { + case 0: asm (""); a[i] = - i - 1; b[i] = i + 1; break; + case 1: a[i] = 0; b[i] = 0; break; + case 2: a[i] = i + 1; b[i] = - i - 1; break; + case 3: a[i] = i; b[i] = i + 7; break; + case 4: a[i] = i; b[i] = i; break; + case 5: a[i] = i + 16; b[i] = i + 3; break; + case 6: a[i] = - i - 5; b[i] = - i; break; + case 7: a[i] = - i; b[i] = - i; break; + case 8: a[i] = - i; b[i] = - i - 7; break; + } + d[i] = i; + e[i] = 2 * i; + } + f1 (); + for (i = 0; i < N; i++) + if (k[i] != ((i % 3) == 0 ? 17 : 0)) + abort (); + f2 (); + for (i = 0; i < N; i++) + if (k[i] != ((i % 3) == 0 ? 0 : 24)) + abort (); + f3 (); + for (i = 0; i < N; i++) + if (k[i] != ((i % 3) == 0 ? 51 : 12)) + abort (); + f4 (); + for (i = 0; i < N; i++) + if (f[i] != ((i % 3) == 0 ? d[i] : e[i])) + abort (); + for (i = 0; i < N; i++) + { + switch (i % 9) + { + case 0: asm (""); d[i] = - i - 1; e[i] = i + 1; break; + case 1: d[i] = 0; e[i] = 0; break; + case 2: d[i] = i + 1; e[i] = - i - 1; break; + case 3: d[i] = i; e[i] = i + 7; break; + case 4: d[i] = i; e[i] = i; break; + case 5: d[i] = i + 16; e[i] = i + 3; break; + case 6: d[i] = - i - 5; e[i] = - i; break; + case 7: d[i] = - i; e[i] = - i; break; + case 8: d[i] = - i; e[i] = - i - 7; break; + } + a[i] = i; + b[i] = i / 2; + } + f5 (); + for (i = 0; i < N; i++) + if (c[i] != ((i % 3) == 0 ? a[i] : b[i])) + abort (); + + return 0; +} + +/* { dg-final { scan-tree-dump-times "note: vectorized 1 loops" 5 "vect" } } */ +/* { dg-final { cleanup-tree-dump "vect" } } */ diff --git a/gcc/testsuite/lib/target-supports.exp b/gcc/testsuite/lib/target-supports.exp index 5d236f7..550d534 100644 --- a/gcc/testsuite/lib/target-supports.exp +++ b/gcc/testsuite/lib/target-supports.exp @@ -3234,6 +3234,26 @@ proc check_effective_target_vect_condition { } { return $et_vect_cond_saved } +# Return 1 if the target supports vector conditional operations where +# the comparison has different type from the lhs, 0 otherwise. + +proc check_effective_target_vect_cond_mixed { } { + global et_vect_cond_mixed_saved + + if [info exists et_vect_cond_mixed_saved] { + verbose "check_effective_target_vect_cond_mixed: using cached result" 2 + } else { + set et_vect_cond_mixed_saved 0 + if { [istarget i?86-*-*] + || [istarget x86_64-*-*] } { + set et_vect_cond_mixed_saved 1 + } + } + + verbose "check_effective_target_vect_cond_mixed: returning $et_vect_cond_mixed_saved" 2 + return $et_vect_cond_mixed_saved +} + # Return 1 if the target supports vector char multiplication, 0 otherwise. proc check_effective_target_vect_char_mult { } { diff --git a/gcc/tree-vect-patterns.c b/gcc/tree-vect-patterns.c index f0949a3..0cd350d 100644 --- a/gcc/tree-vect-patterns.c +++ b/gcc/tree-vect-patterns.c @@ -49,12 +49,15 @@ static gimple vect_recog_dot_prod_pattern (VEC (gimple, heap) **, tree *, static gimple vect_recog_pow_pattern (VEC (gimple, heap) **, tree *, tree *); static gimple vect_recog_over_widening_pattern (VEC (gimple, heap) **, tree *, tree *); +static gimple vect_recog_mixed_size_cond_pattern (VEC (gimple, heap) **, + 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_pow_pattern, - vect_recog_over_widening_pattern}; + vect_recog_over_widening_pattern, + vect_recog_mixed_size_cond_pattern}; /* Function widened_name_p @@ -1211,6 +1214,120 @@ vect_recog_over_widening_pattern (VEC (gimple, heap) **stmts, } +/* Function vect_recog_mixed_size_cond_pattern + + Try to find the following pattern: + + type x_t, y_t; + TYPE a_T, b_T, c_T; + loop: + S1 a_T = x_t CMP y_t ? b_T : c_T; + + where type 'TYPE' is an integral type which has different size + from 'type'. b_T and c_T are constants and if 'TYPE' is wider + than 'type', the constants need to fit into an integer type + with the same width as 'type'. + + 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 pattern. + Additionally a def_stmt is added. + + a_it = x_t CMP y_t ? b_it : c_it; + a_T = (TYPE) a_it; */ + +static gimple +vect_recog_mixed_size_cond_pattern (VEC (gimple, heap) **stmts, tree *type_in, + tree *type_out) +{ + gimple last_stmt = VEC_index (gimple, *stmts, 0); + tree cond_expr, then_clause, else_clause; + stmt_vec_info stmt_vinfo = vinfo_for_stmt (last_stmt), def_stmt_info; + tree type, vectype, comp_vectype, itype, vecitype; + enum machine_mode cmpmode; + gimple pattern_stmt, def_stmt; + loop_vec_info loop_vinfo = STMT_VINFO_LOOP_VINFO (stmt_vinfo); + + if (!is_gimple_assign (last_stmt) + || gimple_assign_rhs_code (last_stmt) != COND_EXPR + || STMT_VINFO_DEF_TYPE (stmt_vinfo) != vect_internal_def) + return NULL; + + cond_expr = gimple_assign_rhs1 (last_stmt); + then_clause = gimple_assign_rhs2 (last_stmt); + else_clause = gimple_assign_rhs3 (last_stmt); + + if (TREE_CODE (then_clause) != INTEGER_CST + || TREE_CODE (else_clause) != INTEGER_CST) + return NULL; + + if (!vect_is_simple_cond (cond_expr, loop_vinfo, &comp_vectype) + || !comp_vectype) + return NULL; + + type = gimple_expr_type (last_stmt); + cmpmode = GET_MODE_INNER (TYPE_MODE (comp_vectype)); + + if (GET_MODE_BITSIZE (TYPE_MODE (type)) == GET_MODE_BITSIZE (cmpmode)) + return NULL; + + vectype = get_vectype_for_scalar_type (type); + if (vectype == NULL_TREE) + return NULL; + + if (expand_vec_cond_expr_p (vectype, comp_vectype)) + return NULL; + + itype = build_nonstandard_integer_type (GET_MODE_BITSIZE (cmpmode), + TYPE_UNSIGNED (type)); + if (itype == NULL_TREE + || GET_MODE_BITSIZE (TYPE_MODE (itype)) != GET_MODE_BITSIZE (cmpmode)) + return NULL; + + vecitype = get_vectype_for_scalar_type (itype); + if (vecitype == NULL_TREE) + return NULL; + + if (!expand_vec_cond_expr_p (vecitype, comp_vectype)) + return NULL; + + if (GET_MODE_BITSIZE (TYPE_MODE (type)) > GET_MODE_BITSIZE (cmpmode)) + { + if (!int_fits_type_p (then_clause, itype) + || !int_fits_type_p (else_clause, itype)) + return NULL; + } + + def_stmt + = gimple_build_assign_with_ops3 (COND_EXPR, + vect_recog_temp_ssa_var (itype, NULL), + unshare_expr (cond_expr), + fold_convert (itype, then_clause), + fold_convert (itype, else_clause)); + pattern_stmt + = gimple_build_assign_with_ops (NOP_EXPR, + vect_recog_temp_ssa_var (type, NULL), + gimple_assign_lhs (def_stmt), NULL_TREE); + + STMT_VINFO_PATTERN_DEF_STMT (stmt_vinfo) = def_stmt; + def_stmt_info = new_stmt_vec_info (def_stmt, loop_vinfo, NULL); + set_vinfo_for_stmt (def_stmt, def_stmt_info); + STMT_VINFO_VECTYPE (def_stmt_info) = vecitype; + *type_in = vecitype; + *type_out = vectype; + + return pattern_stmt; +} + + /* Mark statements that are involved in a pattern. */ static inline void @@ -1238,14 +1355,18 @@ vect_mark_pattern_stmts (gimple orig_stmt, gimple pattern_stmt, if (STMT_VINFO_PATTERN_DEF_STMT (pattern_stmt_info)) { def_stmt = STMT_VINFO_PATTERN_DEF_STMT (pattern_stmt_info); - set_vinfo_for_stmt (def_stmt, - new_stmt_vec_info (def_stmt, loop_vinfo, NULL)); - gimple_set_bb (def_stmt, gimple_bb (orig_stmt)); def_stmt_info = vinfo_for_stmt (def_stmt); + if (def_stmt_info == NULL) + { + def_stmt_info = new_stmt_vec_info (def_stmt, loop_vinfo, NULL); + set_vinfo_for_stmt (def_stmt, def_stmt_info); + } + gimple_set_bb (def_stmt, gimple_bb (orig_stmt)); STMT_VINFO_RELATED_STMT (def_stmt_info) = orig_stmt; STMT_VINFO_DEF_TYPE (def_stmt_info) = STMT_VINFO_DEF_TYPE (orig_stmt_info); - STMT_VINFO_VECTYPE (def_stmt_info) = pattern_vectype; + if (STMT_VINFO_VECTYPE (def_stmt_info) == NULL_TREE) + STMT_VINFO_VECTYPE (def_stmt_info) = pattern_vectype; } } diff --git a/gcc/tree-vect-stmts.c b/gcc/tree-vect-stmts.c index 8c2edad..2110c96 100644 --- a/gcc/tree-vect-stmts.c +++ b/gcc/tree-vect-stmts.c @@ -652,9 +652,25 @@ vect_mark_stmts_to_be_vectorized (loop_vec_info loop_vinfo) have to scan the RHS or function arguments instead. */ if (is_gimple_assign (stmt)) { - for (i = 1; i < gimple_num_ops (stmt); i++) + enum tree_code rhs_code = gimple_assign_rhs_code (stmt); + tree op = gimple_assign_rhs1 (stmt); + + i = 1; + if (rhs_code == COND_EXPR && COMPARISON_CLASS_P (op)) + { + if (!process_use (stmt, TREE_OPERAND (op, 0), loop_vinfo, + live_p, relevant, &worklist) + || !process_use (stmt, TREE_OPERAND (op, 1), loop_vinfo, + live_p, relevant, &worklist)) + { + VEC_free (gimple, heap, worklist); + return false; + } + i = 2; + } + for (; i < gimple_num_ops (stmt); i++) { - tree op = gimple_op (stmt, i); + op = gimple_op (stmt, i); if (!process_use (stmt, op, loop_vinfo, live_p, relevant, &worklist)) { @@ -4682,7 +4698,7 @@ vectorizable_load (gimple stmt, gimple_stmt_iterator *gsi, gimple *vec_stmt, Returns whether a COND can be vectorized. Checks whether condition operands are supportable using vec_is_simple_use. */ -static bool +bool vect_is_simple_cond (tree cond, loop_vec_info loop_vinfo, tree *comp_vectype) { tree lhs, rhs; diff --git a/gcc/tree-vectorizer.h b/gcc/tree-vectorizer.h index 3fe8b62..2782082 100644 --- a/gcc/tree-vectorizer.h +++ b/gcc/tree-vectorizer.h @@ -1,5 +1,5 @@ /* Vectorizer - Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 + Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc. Contributed by Dorit Naishlos @@ -818,6 +818,7 @@ extern bool vect_transform_stmt (gimple, gimple_stmt_iterator *, bool *, slp_tree, slp_instance); extern void vect_remove_stores (gimple); extern bool vect_analyze_stmt (gimple, bool *, slp_tree); +extern bool vect_is_simple_cond (tree, loop_vec_info, tree *); extern bool vectorizable_condition (gimple, gimple_stmt_iterator *, gimple *, tree, int); extern void vect_get_load_cost (struct data_reference *, int, bool, @@ -902,7 +903,7 @@ extern void vect_slp_transform_bb (basic_block); Additional pattern recognition functions can (and will) be added in the future. */ typedef gimple (* vect_recog_func_ptr) (VEC (gimple, heap) **, tree *, tree *); -#define NUM_PATTERNS 5 +#define NUM_PATTERNS 6 void vect_pattern_recog (loop_vec_info); /* In tree-vectorizer.c. */ -- 2.7.4