Hi
Here is a patch with vector comparison only.
Comparison is expanded using VEC_COND_EXPR, conversions between the
different types inside the VEC_COND_EXPR are happening in optabs.c.
The comparison generally works, however, the x86 backend does not
recognize vectors of all 1s of type float and double, which is very
bad, but I hope it could be fixed easily. Here is my humble attempt:
Index: gcc/config/i386/predicates.md
===================================================================
--- gcc/config/i386/predicates.md (revision 177665)
+++ gcc/config/i386/predicates.md (working copy)
@@ -763,7 +763,19 @@ (define_predicate "vector_all_ones_opera
for (i = 0; i < nunits; ++i)
{
rtx x = CONST_VECTOR_ELT (op, i);
- if (x != constm1_rtx)
+ rtx y;
+
+ if (GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT)
+ {
+ REAL_VALUE_TYPE r;
+ REAL_VALUE_FROM_INT (r, -1, -1, GET_MODE (x));
+ y = CONST_DOUBLE_FROM_REAL_VALUE (r, GET_MODE (x));
+ }
+ else
+ y = constm1_rtx;
+
+ /* if (x != constm1_rtx) */
+ if (!rtx_equal_p (x, y))
return false;
}
return true;
But the problem I have here is that -1 actually converts to -1.0,
where I need to treat -0x1 as float. Something like:
int p = -1;
void *x = &p;
float r = *((float *)x);
Is there any way to do that in this context? Or may be there is
another way to support real-typed vectors of -1 as constants?
ChangeLog
20011-08-27 Artjoms Sinkarovs <[email protected]>
gcc/
* optabs.c (vector_compare_rtx): Allow comparison operands
and vcond operands have different type.
(expand_vec_cond_expr): Convert operands in case they do
not match.
* fold-const.c (constant_boolean_node): Adjust the meaning
of boolean for vector types: true = {-1,..}, false = {0,..}.
(fold_unary_loc): Avoid conversion of vector comparison to
boolean type.
* expr.c (expand_expr_real_2): Expand vector comparison by
building an appropriate VEC_COND_EXPR.
* c-typeck.c (build_binary_op): Typecheck vector comparisons.
(c_objc_common_truthvalue_conversion): Adjust.
* gimplify.c (gimplify_expr): Support vector comparison
in gimple.
* tree.def: Adjust comment.
* tree-vect-generic.c (do_compare): Helper function.
(expand_vector_comparison): Check if hardware supports
vector comparison of the given type or expand vector
piecewise.
(expand_vector_operation): Treat comparison as binary
operation of vector type.
(expand_vector_operations_1): Adjust.
* tree-cfg.c (verify_gimple_comparison): Adjust.
gcc/config/i386
* i386.c (ix86_expand_sse_movcc): Consider a case when
vcond operators are {-1,..} and {0,..}.
gcc/doc
* extend.texi: Adjust.
gcc/testsuite
* gcc.c-torture/execute/vector-compare-1.c: New test.
* gcc.c-torture/execute/vector-compare-2.c: New test.
* gcc.dg/vector-compare-1.c: New test.
* gcc.dg/vector-compare-2.c: New test.
Bootstrapped and tested on x86_64-unknown-linux-gnu.
Artem.
Index: gcc/doc/extend.texi
===================================================================
--- gcc/doc/extend.texi (revision 177665)
+++ gcc/doc/extend.texi (working copy)
@@ -6553,6 +6553,29 @@ invoke undefined behavior at runtime. W
accesses for vector subscription can be enabled with
@option{-Warray-bounds}.
+In GNU C vector comparison is supported within standard comparison
+operators: @code{==, !=, <, <=, >, >=}. Comparison operands can be
+vector expressions of integer-type or real-type. Comparison between
+integer-type vectors and real-type vectors are not supported. The
+result of the comparison is a vector of the same width and number of
+elements as the comparison operands with a signed integral element
+type.
+
+Vectors are compared element-wise producing 0 when comparison is false
+and -1 (constant of the appropriate type where all bits are set)
+otherwise. Consider the following example.
+
+@smallexample
+typedef int v4si __attribute__ ((vector_size (16)));
+
+v4si a = @{1,2,3,4@};
+v4si b = @{3,2,1,4@};
+v4si c;
+
+c = a > b; /* The result would be @{0, 0,-1, 0@} */
+c = a == b; /* The result would be @{0,-1, 0,-1@} */
+@end smallexample
+
You can declare variables and use them in function calls and returns, as
well as in assignments and some casts. You can specify a vector type as
a return type for a function. Vector types can also be used as function
Index: gcc/optabs.c
===================================================================
--- gcc/optabs.c (revision 177665)
+++ gcc/optabs.c (working copy)
@@ -6502,7 +6502,8 @@ get_rtx_code (enum tree_code tcode, bool
unsigned operators. Do not generate compare instruction. */
static rtx
-vector_compare_rtx (tree cond, bool unsignedp, enum insn_code icode)
+vector_compare_rtx (tree cond, bool unsignedp, enum insn_code icode,
+ bool legitimize)
{
struct expand_operand ops[2];
enum rtx_code rcode;
@@ -6525,7 +6526,8 @@ vector_compare_rtx (tree cond, bool unsi
create_input_operand (&ops[0], rtx_op0, GET_MODE (rtx_op0));
create_input_operand (&ops[1], rtx_op1, GET_MODE (rtx_op1));
- if (!maybe_legitimize_operands (icode, 4, 2, ops))
+
+ if (legitimize && !maybe_legitimize_operands (icode, 4, 2, ops))
gcc_unreachable ();
return gen_rtx_fmt_ee (rcode, VOIDmode, ops[0].value, ops[1].value);
}
@@ -6566,24 +6568,49 @@ expand_vec_cond_expr (tree vec_cond_type
enum insn_code icode;
rtx comparison, rtx_op1, rtx_op2;
enum machine_mode mode = TYPE_MODE (vec_cond_type);
- bool unsignedp = TYPE_UNSIGNED (vec_cond_type);
+ bool unsignedp;
+ enum machine_mode comp_mode;
+ tree comp_type;
+
+ gcc_assert (COMPARISON_CLASS_P (op0));
+
+ comp_type = TREE_TYPE (TREE_OPERAND (op0, 0));
+ comp_mode = TYPE_MODE (comp_type);
+ unsignedp = TYPE_UNSIGNED (comp_type);
+
+ if (mode != comp_mode)
+ icode = get_vcond_icode (comp_type, comp_mode);
+ else
+ icode = get_vcond_icode (vec_cond_type, mode);
- icode = get_vcond_icode (vec_cond_type, mode);
if (icode == CODE_FOR_nothing)
return 0;
- comparison = vector_compare_rtx (op0, unsignedp, icode);
+ comparison = vector_compare_rtx (op0, unsignedp, icode, mode == comp_mode);
+
rtx_op1 = expand_normal (op1);
rtx_op2 = expand_normal (op2);
-
- create_output_operand (&ops[0], target, mode);
- create_input_operand (&ops[1], rtx_op1, mode);
- create_input_operand (&ops[2], rtx_op2, mode);
- create_fixed_operand (&ops[3], comparison);
- create_fixed_operand (&ops[4], XEXP (comparison, 0));
- create_fixed_operand (&ops[5], XEXP (comparison, 1));
+
+ if (comp_mode != mode)
+ {
+ rtx_op1 = simplify_gen_subreg (comp_mode, rtx_op1,
+ GET_MODE (rtx_op1), 0);
+ rtx_op2 = simplify_gen_subreg (comp_mode, rtx_op2,
+ GET_MODE (rtx_op2), 0);
+ }
+
+ create_output_operand (&ops[0], target, comp_mode);
+ create_input_operand (&ops[1], rtx_op1, comp_mode);
+ create_input_operand (&ops[2], rtx_op2, comp_mode);
+ create_input_operand (&ops[3], comparison, mode);
+ create_input_operand (&ops[4], XEXP (comparison, 0), comp_mode);
+ create_input_operand (&ops[5], XEXP (comparison, 1), comp_mode);
expand_insn (icode, 6, ops);
- return ops[0].value;
+
+ if (mode != comp_mode)
+ return simplify_gen_subreg (mode, ops[0].value, comp_mode, 0);
+ else
+ return ops[0].value;
}
Index: gcc/fold-const.c
===================================================================
--- gcc/fold-const.c (revision 177665)
+++ gcc/fold-const.c (working copy)
@@ -5930,12 +5930,21 @@ extract_muldiv_1 (tree t, tree c, enum t
}
/* Return a node which has the indicated constant VALUE (either 0 or
- 1), and is of the indicated TYPE. */
+ 1 for scalars and is either {-1,-1,..} or {0,0,...} for vectors),
+ and is of the indicated TYPE. */
tree
constant_boolean_node (int value, tree type)
{
- if (type == integer_type_node)
+ if (TREE_CODE (type) == VECTOR_TYPE)
+ {
+ tree tval;
+
+ gcc_assert (TREE_CODE (TREE_TYPE (type)) == INTEGER_TYPE);
+ tval = build_int_cst (TREE_TYPE (type), value ? -1 : 0);
+ return build_vector_from_val (type, tval);
+ }
+ else if (type == integer_type_node)
return value ? integer_one_node : integer_zero_node;
else if (type == boolean_type_node)
return value ? boolean_true_node : boolean_false_node;
@@ -7667,6 +7676,16 @@ fold_unary_loc (location_t loc, enum tre
return build2_loc (loc, TREE_CODE (op0), type,
TREE_OPERAND (op0, 0),
TREE_OPERAND (op0, 1));
+ else if (TREE_CODE (type) == VECTOR_TYPE)
+ {
+ tree el_type = TREE_TYPE (type);
+ tree op_el_type = TREE_TYPE (TREE_TYPE (op0));
+
+ if (el_type == op_el_type)
+ return op0;
+ else
+ build1_loc (loc, VIEW_CONVERT_EXPR, type, op0);
+ }
else if (!INTEGRAL_TYPE_P (type))
return build3_loc (loc, COND_EXPR, type, op0,
fold_convert (type, boolean_true_node),
Index: gcc/testsuite/gcc.c-torture/execute/vector-compare-1.c
===================================================================
--- gcc/testsuite/gcc.c-torture/execute/vector-compare-1.c (revision 0)
+++ gcc/testsuite/gcc.c-torture/execute/vector-compare-1.c (revision 0)
@@ -0,0 +1,123 @@
+#define vector(elcount, type) \
+__attribute__((vector_size((elcount)*sizeof(type)))) type
+
+#define check_compare(count, res, i0, i1, op, fmt) \
+do { \
+ int __i; \
+ for (__i = 0; __i < count; __i ++) { \
+ if ((res)[__i] != ((i0)[__i] op (i1)[__i] ? -1 : 0)) \
+ { \
+ __builtin_printf ("%i != ((" fmt " " #op " " fmt " ? -1 : 0) ", \
+ (res)[__i], (i0)[__i], (i1)[__i]); \
+ __builtin_abort (); \
+ } \
+ } \
+} while (0)
+
+#define test(count, v0, v1, res, fmt); \
+do { \
+ res = (v0 > v1); \
+ check_compare (count, res, v0, v1, >, fmt); \
+ res = (v0 < v1); \
+ check_compare (count, res, v0, v1, <, fmt); \
+ res = (v0 >= v1); \
+ check_compare (count, res, v0, v1, >=, fmt); \
+ res = (v0 <= v1); \
+ check_compare (count, res, v0, v1, <=, fmt); \
+ res = (v0 == v1); \
+ check_compare (count, res, v0, v1, ==, fmt); \
+ res = (v0 != v1); \
+ check_compare (count, res, v0, v1, !=, fmt); \
+} while (0)
+
+
+int main (int argc, char *argv[]) {
+#define INT int
+ vector (4, INT) i0;
+ vector (4, INT) i1;
+ vector (4, int) ires;
+ int i;
+
+ i0 = (vector (4, INT)){argc, 1, 2, 10};
+ i1 = (vector (4, INT)){0, 3, 2, (INT)-23};
+ test (4, i0, i1, ires, "%i");
+#undef INT
+
+#define INT unsigned int
+ vector (4, int) ures;
+ vector (4, INT) u0;
+ vector (4, INT) u1;
+
+ u0 = (vector (4, INT)){argc, 1, 2, 10};
+ u1 = (vector (4, INT)){0, 3, 2, (INT)-23};
+ test (4, u0, u1, ures, "%u");
+#undef INT
+
+
+#define SHORT short
+ vector (8, SHORT) s0;
+ vector (8, SHORT) s1;
+ vector (8, short) sres;
+
+ s0 = (vector (8, SHORT)){argc, 1, 2, 10, 6, 87, (SHORT)-5, 2};
+ s1 = (vector (8, SHORT)){0, 3, 2, (SHORT)-23, 12, 10, (SHORT)-2, 0};
+ test (8, s0, s1, sres, "%i");
+#undef SHORT
+
+#define SHORT unsigned short
+ vector (8, SHORT) us0;
+ vector (8, SHORT) us1;
+ vector (8, short) usres;
+
+ us0 = (vector (8, SHORT)){argc, 1, 2, 10, 6, 87, (SHORT)-5, 2};
+ us1 = (vector (8, SHORT)){0, 3, 2, (SHORT)-23, 12, 10, (SHORT)-2, 0};
+ test (8, us0, us1, usres, "%u");
+#undef SHORT
+
+#define CHAR signed char
+ vector (16, CHAR) c0;
+ vector (16, CHAR) c1;
+ vector (16, signed char) cres;
+
+ c0 = (vector (16, CHAR)){argc, 1, 2, 10, 6, 87, (CHAR)-5, 2, \
+ argc, 1, 2, 10, 6, 87, (CHAR)-5, 2 };
+
+ c1 = (vector (16, CHAR)){0, 3, 2, (CHAR)-23, 12, 10, (CHAR)-2, 0, \
+ 0, 3, 2, (CHAR)-23, 12, 10, (CHAR)-2, 0};
+ test (16, c0, c1, cres, "%i");
+#undef CHAR
+
+#define CHAR unsigned char
+ vector (16, CHAR) uc0;
+ vector (16, CHAR) uc1;
+ vector (16, signed char) ucres;
+
+ uc0 = (vector (16, CHAR)){argc, 1, 2, 10, 6, 87, (CHAR)-5, 2, \
+ argc, 1, 2, 10, 6, 87, (CHAR)-5, 2 };
+
+ uc1 = (vector (16, CHAR)){0, 3, 2, (CHAR)-23, 12, 10, (CHAR)-2, 0, \
+ 0, 3, 2, (CHAR)-23, 12, 10, (CHAR)-2, 0};
+ test (16, uc0, uc1, ucres, "%u");
+#undef CHAR
+/* Float comparison. */
+ vector (4, float) f0;
+ vector (4, float) f1;
+ vector (4, int) ifres;
+
+ f0 = (vector (4, float)){(float)argc, 1., 2., 10.};
+ f1 = (vector (4, float)){0., 3., 2., (float)-23};
+ test (4, f0, f1, ifres, "%f");
+
+/* Double comparison. */
+ vector (2, double) d0;
+ vector (2, double) d1;
+ vector (2, long) idres;
+
+ d0 = (vector (2, double)){(double)argc, 10.};
+ d1 = (vector (2, double)){0., (double)-23};
+ test (2, d0, d1, idres, "%f");
+
+
+ return 0;
+}
+
Index: gcc/testsuite/gcc.c-torture/execute/vector-compare-2.c
===================================================================
--- gcc/testsuite/gcc.c-torture/execute/vector-compare-2.c (revision 0)
+++ gcc/testsuite/gcc.c-torture/execute/vector-compare-2.c (revision 0)
@@ -0,0 +1,27 @@
+#define vector(elcount, type) \
+__attribute__((vector_size((elcount)*sizeof(type)))) type
+
+/* Check that constant folding in
+ these simple cases works. */
+vector (4, int)
+foo (vector (4, int) x)
+{
+ return (x == x) + (x != x) + (x > x)
+ + (x < x) + (x >= x) + (x <= x);
+}
+
+int
+main (int argc, char *argv[])
+{
+ vector (4, int) t = {argc, 2, argc, 42};
+ vector (4, int) r;
+ int i;
+
+ r = foo (t);
+
+ for (i = 0; i < 4; i++)
+ if (r[i] != -3)
+ __builtin_abort ();
+
+ return 0;
+}
Index: gcc/testsuite/gcc.dg/vector-compare-1.c
===================================================================
--- gcc/testsuite/gcc.dg/vector-compare-1.c (revision 0)
+++ gcc/testsuite/gcc.dg/vector-compare-1.c (revision 0)
@@ -0,0 +1,17 @@
+/* { dg-do compile } */
+#define vector(elcount, type) \
+__attribute__((vector_size((elcount)*sizeof(type)))) type
+
+void
+foo (vector (4, int) x, vector (4, float) y)
+{
+ vector (4, int) p4;
+ vector (4, int) r4;
+ vector (4, unsigned int) q4;
+ vector (8, int) r8;
+ vector (4, float) f4;
+
+ r4 = x > y; /* { dg-error "comparing vectors with different element
types" } */
+ r8 = (x != p4); /* { dg-error "incompatible types when assigning to type"
} */
+ r8 == r4; /* { dg-error "comparing vectors with different number of
elements" } */
+}
Index: gcc/testsuite/gcc.dg/vector-compare-2.c
===================================================================
--- gcc/testsuite/gcc.dg/vector-compare-2.c (revision 0)
+++ gcc/testsuite/gcc.dg/vector-compare-2.c (revision 0)
@@ -0,0 +1,26 @@
+/* { dg-do compile } */
+
+/* Test if C_MAYBE_CONST are folded correctly when
+ creating VEC_COND_EXPR. */
+
+typedef int vec __attribute__((vector_size(16)));
+
+vec i,j;
+extern vec a, b, c;
+
+extern int p, q, z;
+extern vec foo (int);
+
+vec
+foo (int x)
+{
+ return foo (p ? q :z) > a;
+}
+
+vec
+bar (int x)
+{
+ return b > foo (p ? q :z);
+}
+
+
Index: gcc/expr.c
===================================================================
--- gcc/expr.c (revision 177665)
+++ gcc/expr.c (working copy)
@@ -8440,6 +8440,29 @@ expand_expr_real_2 (sepops ops, rtx targ
case UNGE_EXPR:
case UNEQ_EXPR:
case LTGT_EXPR:
+ if (TREE_CODE (ops->type) == VECTOR_TYPE)
+ {
+ enum tree_code code = ops->code;
+ tree arg0 = ops->op0;
+ tree arg1 = ops->op1;
+ tree el_type = TREE_TYPE (TREE_TYPE (arg0));
+ tree t, ifexp, if_true, if_false;
+
+ el_type = build_nonstandard_integer_type
+ (GET_MODE_BITSIZE (TYPE_MODE (el_type)), 0);
+
+ ifexp = build2 (code, type, arg0, arg1);
+ if_true = build_vector_from_val (type, build_int_cst (el_type, -1));
+ if_false = build_vector_from_val (type, build_int_cst (el_type, 0));
+
+ t = build3 (VEC_COND_EXPR, type, ifexp, if_true, if_false);
+
+ return expand_expr (t,
+ modifier != EXPAND_STACK_PARM ? target :
NULL_RTX,
+ tmode != VOIDmode ? tmode : mode,
+ modifier);
+ }
+
temp = do_store_flag (ops,
modifier != EXPAND_STACK_PARM ? target : NULL_RTX,
tmode != VOIDmode ? tmode : mode);
Index: gcc/c-typeck.c
===================================================================
--- gcc/c-typeck.c (revision 177665)
+++ gcc/c-typeck.c (working copy)
@@ -9906,6 +9906,29 @@ build_binary_op (location_t location, en
case EQ_EXPR:
case NE_EXPR:
+ if (code0 == VECTOR_TYPE && code1 == VECTOR_TYPE)
+ {
+ tree intt;
+ if (TREE_TYPE (type0) != TREE_TYPE (type1))
+ {
+ error_at (location, "comparing vectors with different "
+ "element types");
+ return error_mark_node;
+ }
+
+ if (TYPE_VECTOR_SUBPARTS (type0) != TYPE_VECTOR_SUBPARTS (type1))
+ {
+ error_at (location, "comparing vectors with different "
+ "number of elements");
+ return error_mark_node;
+ }
+
+ /* Always construct signed integer vector type. */
+ intt = c_common_type_for_size (TYPE_PRECISION (TREE_TYPE (type0)),0);
+ result_type = build_vector_type (intt, TYPE_VECTOR_SUBPARTS (type0));
+ converted = 1;
+ break;
+ }
if (FLOAT_TYPE_P (type0) || FLOAT_TYPE_P (type1))
warning_at (location,
OPT_Wfloat_equal,
@@ -10018,6 +10041,29 @@ build_binary_op (location_t location, en
case GE_EXPR:
case LT_EXPR:
case GT_EXPR:
+ if (code0 == VECTOR_TYPE && code1 == VECTOR_TYPE)
+ {
+ tree intt;
+ if (TREE_TYPE (type0) != TREE_TYPE (type1))
+ {
+ error_at (location, "comparing vectors with different "
+ "element types");
+ return error_mark_node;
+ }
+
+ if (TYPE_VECTOR_SUBPARTS (type0) != TYPE_VECTOR_SUBPARTS (type1))
+ {
+ error_at (location, "comparing vectors with different "
+ "number of elements");
+ return error_mark_node;
+ }
+
+ /* Always construct signed integer vector type. */
+ intt = c_common_type_for_size (TYPE_PRECISION (TREE_TYPE (type0)),0);
+ result_type = build_vector_type (intt, TYPE_VECTOR_SUBPARTS (type0));
+ converted = 1;
+ break;
+ }
build_type = integer_type_node;
if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE
|| code0 == FIXED_POINT_TYPE)
@@ -10425,6 +10471,10 @@ c_objc_common_truthvalue_conversion (loc
case FUNCTION_TYPE:
gcc_unreachable ();
+ case VECTOR_TYPE:
+ error_at (location, "used vector type where scalar is required");
+ return error_mark_node;
+
default:
break;
}
Index: gcc/gimplify.c
===================================================================
--- gcc/gimplify.c (revision 177665)
+++ gcc/gimplify.c (working copy)
@@ -7348,6 +7348,11 @@ gimplify_expr (tree *expr_p, gimple_seq
{
tree type = TREE_TYPE (TREE_OPERAND (*expr_p, 1));
+ /* Vector comparisons is a valid gimple expression
+ which could be lowered down later. */
+ if (TREE_CODE (type) == VECTOR_TYPE)
+ goto expr_2;
+
if (!AGGREGATE_TYPE_P (type))
{
tree org_type = TREE_TYPE (*expr_p);
Index: gcc/tree.def
===================================================================
--- gcc/tree.def (revision 177665)
+++ gcc/tree.def (working copy)
@@ -704,7 +704,10 @@ DEFTREECODE (TRUTH_NOT_EXPR, "truth_not_
The others are allowed only for integer (or pointer or enumeral)
or real types.
In all cases the operands will have the same type,
- and the value is always the type used by the language for booleans. */
+ and the value is either the type used by the language for booleans
+ or an integer vector type of the same size and with the same number
+ of elements as the comparison operands. True for a vector of
+ comparison results has all bits set while false is equal to zero. */
DEFTREECODE (LT_EXPR, "lt_expr", tcc_comparison, 2)
DEFTREECODE (LE_EXPR, "le_expr", tcc_comparison, 2)
DEFTREECODE (GT_EXPR, "gt_expr", tcc_comparison, 2)
Index: gcc/tree-vect-generic.c
===================================================================
--- gcc/tree-vect-generic.c (revision 177665)
+++ gcc/tree-vect-generic.c (working copy)
@@ -35,6 +35,10 @@ along with GCC; see the file COPYING3.
#include "expr.h"
#include "optabs.h"
+
+static void expand_vector_operations_1 (gimple_stmt_iterator *);
+
+
/* Build a constant of type TYPE, made of VALUE's bits replicated
every TYPE_SIZE (INNER_TYPE) bits to fit TYPE's precision. */
static tree
@@ -125,6 +129,31 @@ do_binop (gimple_stmt_iterator *gsi, tre
return gimplify_build2 (gsi, code, inner_type, a, b);
}
+
+/* Construct expression (A[BITPOS] code B[BITPOS]) ? -1 : 0
+
+ INNER_TYPE is the type of A and B elements
+
+ returned expression is of signed integer type with the
+ size equal to the size of INNER_TYPE. */
+static tree
+do_compare (gimple_stmt_iterator *gsi, tree inner_type, tree a, tree b,
+ tree bitpos, tree bitsize, enum tree_code code)
+{
+ tree comp_type;
+
+ a = tree_vec_extract (gsi, inner_type, a, bitsize, bitpos);
+ b = tree_vec_extract (gsi, inner_type, b, bitsize, bitpos);
+
+ comp_type = build_nonstandard_integer_type
+ (GET_MODE_BITSIZE (TYPE_MODE (inner_type)), 0);
+
+ return gimplify_build3 (gsi, COND_EXPR, comp_type,
+ fold_build2 (code, boolean_type_node, a, b),
+ build_int_cst (comp_type, -1),
+ build_int_cst (comp_type, 0));
+}
+
/* Expand vector addition to scalars. This does bit twiddling
in order to increase parallelism:
@@ -333,6 +362,24 @@ uniform_vector_p (tree vec)
return NULL_TREE;
}
+/* Try to expand vector comparison expression OP0 CODE OP1 by
+ querying optab if the following expression:
+ VEC_COND_EXPR< OP0 CODE OP1, {-1,...}, {0,...}>
+ can be expanded. */
+static tree
+expand_vector_comparison (gimple_stmt_iterator *gsi, tree type, tree op0,
+ tree op1, enum tree_code code)
+{
+ tree t;
+ if (! expand_vec_cond_expr_p (TREE_TYPE (type), TYPE_MODE (type)))
+ t = expand_vector_piecewise (gsi, do_compare, type,
+ TREE_TYPE (TREE_TYPE (op0)), op0, op1, code);
+ else
+ t = NULL_TREE;
+
+ return t;
+}
+
static tree
expand_vector_operation (gimple_stmt_iterator *gsi, tree type, tree
compute_type,
gimple assign, enum tree_code code)
@@ -375,8 +422,27 @@ expand_vector_operation (gimple_stmt_ite
case BIT_NOT_EXPR:
return expand_vector_parallel (gsi, do_unop, type,
gimple_assign_rhs1 (assign),
- NULL_TREE, code);
+ NULL_TREE, code);
+ case EQ_EXPR:
+ case NE_EXPR:
+ case GT_EXPR:
+ case LT_EXPR:
+ case GE_EXPR:
+ case LE_EXPR:
+ case UNEQ_EXPR:
+ case UNGT_EXPR:
+ case UNLT_EXPR:
+ case UNGE_EXPR:
+ case UNLE_EXPR:
+ case LTGT_EXPR:
+ case ORDERED_EXPR:
+ case UNORDERED_EXPR:
+ {
+ tree rhs1 = gimple_assign_rhs1 (assign);
+ tree rhs2 = gimple_assign_rhs2 (assign);
+ return expand_vector_comparison (gsi, type, rhs1, rhs2, code);
+ }
default:
break;
}
@@ -450,11 +516,11 @@ expand_vector_operations_1 (gimple_stmt_
code = gimple_assign_rhs_code (stmt);
rhs_class = get_gimple_rhs_class (code);
+ lhs = gimple_assign_lhs (stmt);
if (rhs_class != GIMPLE_UNARY_RHS && rhs_class != GIMPLE_BINARY_RHS)
return;
- lhs = gimple_assign_lhs (stmt);
rhs1 = gimple_assign_rhs1 (stmt);
type = gimple_expr_type (stmt);
if (rhs_class == GIMPLE_BINARY_RHS)
@@ -598,6 +664,11 @@ expand_vector_operations_1 (gimple_stmt_
gcc_assert (code != VEC_LSHIFT_EXPR && code != VEC_RSHIFT_EXPR);
new_rhs = expand_vector_operation (gsi, type, compute_type, stmt, code);
+
+ /* Leave expression untouched for later expansion. */
+ if (new_rhs == NULL_TREE)
+ return;
+
if (!useless_type_conversion_p (TREE_TYPE (lhs), TREE_TYPE (new_rhs)))
new_rhs = gimplify_build1 (gsi, VIEW_CONVERT_EXPR, TREE_TYPE (lhs),
new_rhs);
Index: gcc/tree-cfg.c
===================================================================
--- gcc/tree-cfg.c (revision 177665)
+++ gcc/tree-cfg.c (working copy)
@@ -3191,6 +3191,38 @@ verify_gimple_comparison (tree type, tre
return true;
}
+ if (TREE_CODE (type) == VECTOR_TYPE)
+ {
+ if (TREE_CODE (op0_type) != VECTOR_TYPE
+ || TREE_CODE (op1_type) != VECTOR_TYPE)
+ {
+ error ("non-vector operands in vector comparison");
+ debug_generic_expr (op0_type);
+ debug_generic_expr (op1_type);
+ return true;
+ }
+
+ if (!useless_type_conversion_p (op0_type, op1_type)
+ && !useless_type_conversion_p (op1_type, op0_type))
+ {
+ error ("type mismatch in vector comparison");
+ debug_generic_expr (op0_type);
+ debug_generic_expr (op1_type);
+ return true;
+ }
+
+ if (TYPE_VECTOR_SUBPARTS (type) != TYPE_VECTOR_SUBPARTS (op0_type)
+ && TYPE_PRECISION (TREE_TYPE (op0_type))
+ != TYPE_PRECISION (TREE_TYPE (type)))
+ {
+ error ("invalid vector comparison resulting type");
+ debug_generic_expr (type);
+ return true;
+ }
+
+ return false;
+ }
+
/* For comparisons we do not have the operations type as the
effective type the comparison is carried out in. Instead
we require that either the first operand is trivially
Index: gcc/config/i386/i386.c
===================================================================
--- gcc/config/i386/i386.c (revision 177665)
+++ gcc/config/i386/i386.c (working copy)
@@ -18434,8 +18434,13 @@ ix86_expand_sse_movcc (rtx dest, rtx cmp
{
enum machine_mode mode = GET_MODE (dest);
rtx t2, t3, x;
-
- if (op_false == CONST0_RTX (mode))
+
+ if (vector_all_ones_operand (op_true, GET_MODE (op_true))
+ && rtx_equal_p (op_false, CONST0_RTX (mode)))
+ {
+ emit_insn (gen_rtx_SET (VOIDmode, dest, cmp));
+ }
+ else if (op_false == CONST0_RTX (mode))
{
op_true = force_reg (mode, op_true);
x = gen_rtx_AND (mode, cmp, op_true);