diff options
author | Jakub Jelinek <jakub@redhat.com> | 2016-10-25 18:26:12 +0200 |
---|---|---|
committer | Jakub Jelinek <jakub@gcc.gnu.org> | 2016-10-25 18:26:12 +0200 |
commit | 96592eeda1f5cb381d91ef78dea3e2666bbdb7b5 (patch) | |
tree | 9f9b788664b48c4b29fde366326af8ab3961d90f /gcc | |
parent | 8c78afcec88be17030623a4290f214928c143b29 (diff) | |
download | gcc-96592eeda1f5cb381d91ef78dea3e2666bbdb7b5.zip gcc-96592eeda1f5cb381d91ef78dea3e2666bbdb7b5.tar.gz gcc-96592eeda1f5cb381d91ef78dea3e2666bbdb7b5.tar.bz2 |
re PR target/78102 (GCC refuses to generate PCMPEQQ instruction for SSE4.1)
PR target/78102
* optabs.def (vcondeq_optab, vec_cmpeq_optab): New optabs.
* optabs.c (expand_vec_cond_expr): For comparison codes
EQ_EXPR and NE_EXPR, attempt vcondeq_optab as fallback.
(expand_vec_cmp_expr): For comparison codes
EQ_EXPR and NE_EXPR, attempt vec_cmpeq_optab as fallback.
* optabs-tree.h (expand_vec_cmp_expr_p, expand_vec_cond_expr_p):
Add enum tree_code argument.
* optabs-query.h (get_vec_cmp_eq_icode, get_vcond_eq_icode): New
inline functions.
* optabs-tree.c (expand_vec_cmp_expr_p): Add CODE argument. For
CODE EQ_EXPR or NE_EXPR, attempt to use vec_cmpeq_optab as
fallback.
(expand_vec_cond_expr_p): Add CODE argument. For CODE EQ_EXPR or
NE_EXPR, attempt to use vcondeq_optab as fallback.
* tree-vect-generic.c (expand_vector_comparison,
expand_vector_divmod, expand_vector_condition): Adjust
expand_vec_cmp_expr_p and expand_vec_cond_expr_p callers.
* tree-vect-stmts.c (vectorizable_condition,
vectorizable_comparison): Likewise.
* tree-vect-patterns.c (vect_recog_mixed_size_cond_pattern,
check_bool_pattern, search_type_for_mask_1): Likewise.
* expr.c (do_store_flag): Likewise.
* doc/md.texi (@code{vec_cmpeq@var{m}@var{n}},
@code{vcondeq@var{m}@var{n}}): Document.
* config/i386/sse.md (vec_cmpeqv2div2di, vcondeq<VI8F_128:mode>v2di):
New expanders.
testsuite/
* gcc.target/i386/pr78102.c: New test.
From-SVN: r241525
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/ChangeLog | 30 | ||||
-rw-r--r-- | gcc/config/i386/sse.md | 27 | ||||
-rw-r--r-- | gcc/doc/md.texi | 16 | ||||
-rw-r--r-- | gcc/expr.c | 2 | ||||
-rw-r--r-- | gcc/optabs-query.h | 18 | ||||
-rw-r--r-- | gcc/optabs-tree.c | 28 | ||||
-rw-r--r-- | gcc/optabs-tree.h | 4 | ||||
-rw-r--r-- | gcc/optabs.c | 14 | ||||
-rw-r--r-- | gcc/optabs.def | 2 | ||||
-rw-r--r-- | gcc/testsuite/ChangeLog | 5 | ||||
-rw-r--r-- | gcc/testsuite/gcc.target/i386/pr78102.c | 24 | ||||
-rw-r--r-- | gcc/tree-vect-generic.c | 8 | ||||
-rw-r--r-- | gcc/tree-vect-patterns.c | 10 | ||||
-rw-r--r-- | gcc/tree-vect-stmts.c | 5 |
14 files changed, 168 insertions, 25 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 9715896..e7ab456 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,33 @@ +2016-10-25 Jakub Jelinek <jakub@redhat.com> + + PR target/78102 + * optabs.def (vcondeq_optab, vec_cmpeq_optab): New optabs. + * optabs.c (expand_vec_cond_expr): For comparison codes + EQ_EXPR and NE_EXPR, attempt vcondeq_optab as fallback. + (expand_vec_cmp_expr): For comparison codes + EQ_EXPR and NE_EXPR, attempt vec_cmpeq_optab as fallback. + * optabs-tree.h (expand_vec_cmp_expr_p, expand_vec_cond_expr_p): + Add enum tree_code argument. + * optabs-query.h (get_vec_cmp_eq_icode, get_vcond_eq_icode): New + inline functions. + * optabs-tree.c (expand_vec_cmp_expr_p): Add CODE argument. For + CODE EQ_EXPR or NE_EXPR, attempt to use vec_cmpeq_optab as + fallback. + (expand_vec_cond_expr_p): Add CODE argument. For CODE EQ_EXPR or + NE_EXPR, attempt to use vcondeq_optab as fallback. + * tree-vect-generic.c (expand_vector_comparison, + expand_vector_divmod, expand_vector_condition): Adjust + expand_vec_cmp_expr_p and expand_vec_cond_expr_p callers. + * tree-vect-stmts.c (vectorizable_condition, + vectorizable_comparison): Likewise. + * tree-vect-patterns.c (vect_recog_mixed_size_cond_pattern, + check_bool_pattern, search_type_for_mask_1): Likewise. + * expr.c (do_store_flag): Likewise. + * doc/md.texi (@code{vec_cmpeq@var{m}@var{n}}, + @code{vcondeq@var{m}@var{n}}): Document. + * config/i386/sse.md (vec_cmpeqv2div2di, vcondeq<VI8F_128:mode>v2di): + New expanders. + 2016-10-25 Jeff Law <law@redhat.com> * config/v850/v850.c (v850_handle_data_area_attribute): Fix fallthru diff --git a/gcc/config/i386/sse.md b/gcc/config/i386/sse.md index fde520f..14fcd67 100644 --- a/gcc/config/i386/sse.md +++ b/gcc/config/i386/sse.md @@ -2652,6 +2652,18 @@ DONE; }) +(define_expand "vec_cmpeqv2div2di" + [(set (match_operand:V2DI 0 "register_operand") + (match_operator:V2DI 1 "" + [(match_operand:V2DI 2 "register_operand") + (match_operand:V2DI 3 "vector_operand")]))] + "TARGET_SSE4_1" +{ + bool ok = ix86_expand_int_vec_cmp (operands); + gcc_assert (ok); + DONE; +}) + (define_expand "vcond<V_512:mode><VF_512:mode>" [(set (match_operand:V_512 0 "register_operand") (if_then_else:V_512 @@ -11159,6 +11171,21 @@ DONE; }) +(define_expand "vcondeq<VI8F_128:mode>v2di" + [(set (match_operand:VI8F_128 0 "register_operand") + (if_then_else:VI8F_128 + (match_operator 3 "" + [(match_operand:V2DI 4 "vector_operand") + (match_operand:V2DI 5 "general_operand")]) + (match_operand:VI8F_128 1) + (match_operand:VI8F_128 2)))] + "TARGET_SSE4_1" +{ + bool ok = ix86_expand_int_vcond (operands); + gcc_assert (ok); + DONE; +}) + (define_mode_iterator VEC_PERM_AVX2 [V16QI V8HI V4SI V2DI V4SF V2DF (V32QI "TARGET_AVX2") (V16HI "TARGET_AVX2") diff --git a/gcc/doc/md.texi b/gcc/doc/md.texi index 201f0a5..335dc61 100644 --- a/gcc/doc/md.texi +++ b/gcc/doc/md.texi @@ -4730,6 +4730,14 @@ value of all-zeros. @item @samp{vec_cmpu@var{m}@var{n}} Similar to @code{vec_cmp@var{m}@var{n}} but perform unsigned vector comparison. +@cindex @code{vec_cmpeq@var{m}@var{n}} instruction pattern +@item @samp{vec_cmpeq@var{m}@var{n}} +Similar to @code{vec_cmp@var{m}@var{n}} but perform equality or non-equality +vector comparison only. If @code{vec_cmp@var{m}@var{n}} +or @code{vec_cmpu@var{m}@var{n}} instruction pattern is supported, +it will be preferred over @code{vec_cmpeq@var{m}@var{n}}, so there is +no need to define this instruction pattern if the others are supported. + @cindex @code{vcond@var{m}@var{n}} instruction pattern @item @samp{vcond@var{m}@var{n}} Output a conditional vector move. Operand 0 is the destination to @@ -4746,6 +4754,14 @@ comparison with a truth value of all-ones and a false value of all-zeros. Similar to @code{vcond@var{m}@var{n}} but performs unsigned vector comparison. +@cindex @code{vcondeq@var{m}@var{n}} instruction pattern +@item @samp{vcondeq@var{m}@var{n}} +Similar to @code{vcond@var{m}@var{n}} but performs equality or +non-equality vector comparison only. If @code{vcond@var{m}@var{n}} +or @code{vcondu@var{m}@var{n}} instruction pattern is supported, +it will be preferred over @code{vcondeq@var{m}@var{n}}, so there is +no need to define this instruction pattern if the others are supported. + @cindex @code{vcond_mask_@var{m}@var{n}} instruction pattern @item @samp{vcond_mask_@var{m}@var{n}} Similar to @code{vcond@var{m}@var{n}} but operand 3 holds a pre-computed @@ -11286,7 +11286,7 @@ do_store_flag (sepops ops, rtx target, machine_mode mode) { tree ifexp = build2 (ops->code, ops->type, arg0, arg1); if (VECTOR_BOOLEAN_TYPE_P (ops->type) - && expand_vec_cmp_expr_p (TREE_TYPE (arg0), ops->type)) + && expand_vec_cmp_expr_p (TREE_TYPE (arg0), ops->type, ops->code)) return expand_vec_cmp_expr (ops->type, ifexp, target); else { diff --git a/gcc/optabs-query.h b/gcc/optabs-query.h index 81bdb3b..840dc79 100644 --- a/gcc/optabs-query.h +++ b/gcc/optabs-query.h @@ -90,6 +90,15 @@ get_vec_cmp_icode (machine_mode vmode, machine_mode mask_mode, bool uns) return convert_optab_handler (tab, vmode, mask_mode); } +/* Return insn code for a comparison operator with VMODE + resultin MASK_MODE (only for EQ/NE). */ + +static inline enum insn_code +get_vec_cmp_eq_icode (machine_mode vmode, machine_mode mask_mode) +{ + return convert_optab_handler (vec_cmpeq_optab, vmode, mask_mode); +} + /* Return insn code for a conditional operator with a comparison in mode CMODE, unsigned if UNS is true, resulting in a value of mode VMODE. */ @@ -113,6 +122,15 @@ get_vcond_mask_icode (machine_mode vmode, machine_mode mmode) return convert_optab_handler (vcond_mask_optab, vmode, mmode); } +/* Return insn code for a conditional operator with a comparison in + mode CMODE (only EQ/NE), resulting in a value of mode VMODE. */ + +static inline enum insn_code +get_vcond_eq_icode (machine_mode vmode, machine_mode cmode) +{ + return convert_optab_handler (vcondeq_optab, vmode, cmode); +} + /* Enumerates the possible extraction_insn operations. */ enum extraction_pattern { EP_insv, EP_extv, EP_extzv }; diff --git a/gcc/optabs-tree.c b/gcc/optabs-tree.c index faac087..28f5344 100644 --- a/gcc/optabs-tree.c +++ b/gcc/optabs-tree.c @@ -305,12 +305,16 @@ supportable_convert_operation (enum tree_code code, and resulting mask with MASK_TYPE. */ bool -expand_vec_cmp_expr_p (tree value_type, tree mask_type) +expand_vec_cmp_expr_p (tree value_type, tree mask_type, enum tree_code code) { - enum insn_code icode = get_vec_cmp_icode (TYPE_MODE (value_type), - TYPE_MODE (mask_type), - TYPE_UNSIGNED (value_type)); - return (icode != CODE_FOR_nothing); + if (get_vec_cmp_icode (TYPE_MODE (value_type), TYPE_MODE (mask_type), + TYPE_UNSIGNED (value_type)) != CODE_FOR_nothing) + return true; + if ((code == EQ_EXPR || code == NE_EXPR) + && (get_vec_cmp_eq_icode (TYPE_MODE (value_type), TYPE_MODE (mask_type)) + != CODE_FOR_nothing)) + return true; + return false; } /* Return TRUE iff, appropriate vector insns are available @@ -318,7 +322,7 @@ expand_vec_cmp_expr_p (tree value_type, tree mask_type) with operand vector types in CMP_OP_TYPE. */ bool -expand_vec_cond_expr_p (tree value_type, tree cmp_op_type) +expand_vec_cond_expr_p (tree value_type, tree cmp_op_type, enum tree_code code) { machine_mode value_mode = TYPE_MODE (value_type); machine_mode cmp_op_mode = TYPE_MODE (cmp_op_type); @@ -328,10 +332,16 @@ expand_vec_cond_expr_p (tree value_type, tree cmp_op_type) return true; if (GET_MODE_SIZE (value_mode) != GET_MODE_SIZE (cmp_op_mode) - || GET_MODE_NUNITS (value_mode) != GET_MODE_NUNITS (cmp_op_mode) - || get_vcond_icode (TYPE_MODE (value_type), TYPE_MODE (cmp_op_type), - TYPE_UNSIGNED (cmp_op_type)) == CODE_FOR_nothing) + || GET_MODE_NUNITS (value_mode) != GET_MODE_NUNITS (cmp_op_mode)) return false; + + if (get_vcond_icode (TYPE_MODE (value_type), TYPE_MODE (cmp_op_type), + TYPE_UNSIGNED (cmp_op_type)) == CODE_FOR_nothing + && ((code != EQ_EXPR && code != NE_EXPR) + || get_vcond_eq_icode (TYPE_MODE (value_type), + TYPE_MODE (cmp_op_type)) == CODE_FOR_nothing)) + return false; + return true; } diff --git a/gcc/optabs-tree.h b/gcc/optabs-tree.h index c3b9280..db72943 100644 --- a/gcc/optabs-tree.h +++ b/gcc/optabs-tree.h @@ -38,8 +38,8 @@ enum optab_subtype optab optab_for_tree_code (enum tree_code, const_tree, enum optab_subtype); bool supportable_convert_operation (enum tree_code, tree, tree, tree *, enum tree_code *); -bool expand_vec_cmp_expr_p (tree, tree); -bool expand_vec_cond_expr_p (tree, tree); +bool expand_vec_cmp_expr_p (tree, tree, enum tree_code); +bool expand_vec_cond_expr_p (tree, tree, enum tree_code); void init_tree_optimization_optabs (tree); #endif diff --git a/gcc/optabs.c b/gcc/optabs.c index f78d998..a4d7a5e 100644 --- a/gcc/optabs.c +++ b/gcc/optabs.c @@ -5636,7 +5636,12 @@ expand_vec_cond_expr (tree vec_cond_type, tree op0, tree op1, tree op2, icode = get_vcond_icode (mode, cmp_op_mode, unsignedp); if (icode == CODE_FOR_nothing) - return 0; + { + if (tcode == EQ_EXPR || tcode == NE_EXPR) + icode = get_vcond_eq_icode (mode, cmp_op_mode); + if (icode == CODE_FOR_nothing) + return 0; + } comparison = vector_compare_rtx (tcode, op0a, op0b, unsignedp, icode, 4); rtx_op1 = expand_normal (op1); @@ -5675,7 +5680,12 @@ expand_vec_cmp_expr (tree type, tree exp, rtx target) icode = get_vec_cmp_icode (vmode, mask_mode, unsignedp); if (icode == CODE_FOR_nothing) - return 0; + { + if (tcode == EQ_EXPR || tcode == NE_EXPR) + icode = get_vec_cmp_eq_icode (vmode, mask_mode); + if (icode == CODE_FOR_nothing) + return 0; + } comparison = vector_compare_rtx (tcode, op0a, op0b, unsignedp, icode, 2); create_output_operand (&ops[0], target, mask_mode); diff --git a/gcc/optabs.def b/gcc/optabs.def index 8a64ce1..f97b5f0 100644 --- a/gcc/optabs.def +++ b/gcc/optabs.def @@ -82,9 +82,11 @@ OPTAB_CD(vec_load_lanes_optab, "vec_load_lanes$a$b") OPTAB_CD(vec_store_lanes_optab, "vec_store_lanes$a$b") OPTAB_CD(vcond_optab, "vcond$a$b") OPTAB_CD(vcondu_optab, "vcondu$a$b") +OPTAB_CD(vcondeq_optab, "vcondeq$a$b") OPTAB_CD(vcond_mask_optab, "vcond_mask_$a$b") OPTAB_CD(vec_cmp_optab, "vec_cmp$a$b") OPTAB_CD(vec_cmpu_optab, "vec_cmpu$a$b") +OPTAB_CD(vec_cmpeq_optab, "vec_cmpeq$a$b") OPTAB_CD(maskload_optab, "maskload$a$b") OPTAB_CD(maskstore_optab, "maskstore$a$b") diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 78a9bda..f985dba 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2016-10-25 Jakub Jelinek <jakub@redhat.com> + + PR target/78102 + * gcc.target/i386/pr78102.c: New test. + 2016-10-25 Fritz Reese <fritzoreese@gmail.com> * gfortran.dg/dec_logical_xor_1.f90: New test. diff --git a/gcc/testsuite/gcc.target/i386/pr78102.c b/gcc/testsuite/gcc.target/i386/pr78102.c new file mode 100644 index 0000000..0fc3326 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr78102.c @@ -0,0 +1,24 @@ +/* PR target/78102 */ +/* { dg-do compile } */ +/* { dg-options "-O2 -mno-sse4.2 -msse4.1" } */ +/* { dg-final { scan-assembler-times "pcmpeqq" 3 } } */ + +#include <x86intrin.h> + +__m128i +foo (const __m128i x, const __m128i y) +{ + return _mm_cmpeq_epi64 (x, y); +} + +__v2di +bar (const __v2di x, const __v2di y) +{ + return x == y; +} + +__v2di +baz (const __v2di x, const __v2di y) +{ + return x != y; +} diff --git a/gcc/tree-vect-generic.c b/gcc/tree-vect-generic.c index 5d4273f..b0b37c7 100644 --- a/gcc/tree-vect-generic.c +++ b/gcc/tree-vect-generic.c @@ -356,8 +356,8 @@ expand_vector_comparison (gimple_stmt_iterator *gsi, tree type, tree op0, tree op1, enum tree_code code) { tree t; - if (!expand_vec_cmp_expr_p (TREE_TYPE (op0), type) - && !expand_vec_cond_expr_p (type, TREE_TYPE (op0))) + if (!expand_vec_cmp_expr_p (TREE_TYPE (op0), type, code) + && !expand_vec_cond_expr_p (type, TREE_TYPE (op0), code)) t = expand_vector_piecewise (gsi, do_compare, type, TREE_TYPE (TREE_TYPE (op0)), op0, op1, code); else @@ -630,7 +630,7 @@ expand_vector_divmod (gimple_stmt_iterator *gsi, tree type, tree op0, } } if (addend == NULL_TREE - && expand_vec_cond_expr_p (type, type)) + && expand_vec_cond_expr_p (type, type, LT_EXPR)) { tree zero, cst, cond, mask_type; gimple *stmt; @@ -878,7 +878,7 @@ expand_vector_condition (gimple_stmt_iterator *gsi) comp_inner_type = TREE_TYPE (TREE_TYPE (a1)); } - if (expand_vec_cond_expr_p (type, TREE_TYPE (a1))) + if (expand_vec_cond_expr_p (type, TREE_TYPE (a1), TREE_CODE (a))) return; /* TODO: try and find a smaller vector type. */ diff --git a/gcc/tree-vect-patterns.c b/gcc/tree-vect-patterns.c index 3dfbc7b..835d9b5 100644 --- a/gcc/tree-vect-patterns.c +++ b/gcc/tree-vect-patterns.c @@ -3073,7 +3073,7 @@ vect_recog_mixed_size_cond_pattern (vec<gimple *> *stmts, tree *type_in, if (vectype == NULL_TREE) return NULL; - if (expand_vec_cond_expr_p (vectype, comp_vectype)) + if (expand_vec_cond_expr_p (vectype, comp_vectype, TREE_CODE (cond_expr))) return NULL; if (itype == NULL_TREE) @@ -3088,7 +3088,7 @@ vect_recog_mixed_size_cond_pattern (vec<gimple *> *stmts, tree *type_in, if (vecitype == NULL_TREE) return NULL; - if (!expand_vec_cond_expr_p (vecitype, comp_vectype)) + if (!expand_vec_cond_expr_p (vecitype, comp_vectype, TREE_CODE (cond_expr))) return NULL; if (GET_MODE_BITSIZE (TYPE_MODE (type)) > cmp_mode_size) @@ -3195,7 +3195,7 @@ check_bool_pattern (tree var, vec_info *vinfo, hash_set<gimple *> &stmts) tree mask_type = get_mask_type_for_scalar_type (TREE_TYPE (rhs1)); if (mask_type - && expand_vec_cmp_expr_p (comp_vectype, mask_type)) + && expand_vec_cmp_expr_p (comp_vectype, mask_type, rhs_code)) return false; if (TREE_CODE (TREE_TYPE (rhs1)) != INTEGER_TYPE) @@ -3209,7 +3209,7 @@ check_bool_pattern (tree var, vec_info *vinfo, hash_set<gimple *> &stmts) } else vecitype = comp_vectype; - if (! expand_vec_cond_expr_p (vecitype, comp_vectype)) + if (! expand_vec_cond_expr_p (vecitype, comp_vectype, rhs_code)) return false; } else @@ -3537,7 +3537,7 @@ search_type_for_mask_1 (tree var, vec_info *vinfo, mask_type = get_mask_type_for_scalar_type (TREE_TYPE (rhs1)); if (!mask_type - || !expand_vec_cmp_expr_p (comp_vectype, mask_type)) + || !expand_vec_cmp_expr_p (comp_vectype, mask_type, rhs_code)) { res = NULL_TREE; break; diff --git a/gcc/tree-vect-stmts.c b/gcc/tree-vect-stmts.c index d698785..1d17156 100644 --- a/gcc/tree-vect-stmts.c +++ b/gcc/tree-vect-stmts.c @@ -7710,7 +7710,8 @@ vectorizable_condition (gimple *stmt, gimple_stmt_iterator *gsi, if (!vec_stmt) { STMT_VINFO_TYPE (stmt_info) = condition_vec_info_type; - return expand_vec_cond_expr_p (vectype, comp_vectype); + return expand_vec_cond_expr_p (vectype, comp_vectype, + TREE_CODE (cond_expr)); } /* Transform. */ @@ -8013,7 +8014,7 @@ vectorizable_comparison (gimple *stmt, gimple_stmt_iterator *gsi, vect_model_simple_cost (stmt_info, ncopies * (1 + (bitop2 != NOP_EXPR)), dts, NULL, NULL); if (bitop1 == NOP_EXPR) - return expand_vec_cmp_expr_p (vectype, mask_type); + return expand_vec_cmp_expr_p (vectype, mask_type, code); else { machine_mode mode = TYPE_MODE (vectype); |