diff mbox

Vector Comparison patch

Message ID CABYV9SWEZCwQTFYxnoTYNNLXyv85j++K-tLh6KQXqEMzAjhRGw@mail.gmail.com
State New
Headers show

Commit Message

Artem Shinkarov Aug. 25, 2011, 6:20 a.m. UTC
Here is a cleaned-up patch without the hook. Mostly it works in a way
we discussed.

So I think it is a right time to do something about vcond patterns,
which would allow me to get rid of conversions that I need to put all
over the code.

Also at the moment the patch breaks lto frontend with a simple example:
#define vector(elcount, type)  \
__attribute__((vector_size((elcount)*sizeof(type)))) type

int main (int argc, char *argv[]) {
    vector (4, float) f0;
    vector (4, float) f1;

    f0 =  f1 != f0
          ? (vector (4, float)){-1,-1,-1,-1} : (vector (4, float)){0,0,0,0};

    return (int)f0[argc];
}

test-lto.c:8:14: internal compiler error: in convert, at lto/lto-lang.c:1244

I looked into the file, the conversion function is defined as
gcc_unreachable (). I am not very familiar with lto, so I don't really
know what is the right way to treat the conversions.

And I seriously need help with backend patterns.


Thanks,
Artem.

Comments

Richard Biener Aug. 25, 2011, 7:34 a.m. UTC | #1
On Thu, Aug 25, 2011 at 8:20 AM, Artem Shinkarov
<artyom.shinkaroff@gmail.com> wrote:
> Here is a cleaned-up patch without the hook. Mostly it works in a way
> we discussed.
>
> So I think it is a right time to do something about vcond patterns,
> which would allow me to get rid of conversions that I need to put all
> over the code.
>
> Also at the moment the patch breaks lto frontend with a simple example:
> #define vector(elcount, type)  \
> __attribute__((vector_size((elcount)*sizeof(type)))) type
>
> int main (int argc, char *argv[]) {
>    vector (4, float) f0;
>    vector (4, float) f1;
>
>    f0 =  f1 != f0
>          ? (vector (4, float)){-1,-1,-1,-1} : (vector (4, float)){0,0,0,0};
>
>    return (int)f0[argc];
> }
>
> test-lto.c:8:14: internal compiler error: in convert, at lto/lto-lang.c:1244
>
> I looked into the file, the conversion function is defined as
> gcc_unreachable (). I am not very familiar with lto, so I don't really
> know what is the right way to treat the conversions.

convert cannot be called from the middle-end, instead use fold_convert.

> And I seriously need help with backend patterns.

I'll look at the patch in detail later today.

Richard.

>
> Thanks,
> Artem.
>
Artem Shinkarov Aug. 25, 2011, 7:50 a.m. UTC | #2
On Thu, Aug 25, 2011 at 8:34 AM, Richard Guenther
<richard.guenther@gmail.com> wrote:
> On Thu, Aug 25, 2011 at 8:20 AM, Artem Shinkarov
> <artyom.shinkaroff@gmail.com> wrote:
>> Here is a cleaned-up patch without the hook. Mostly it works in a way
>> we discussed.
>>
>> So I think it is a right time to do something about vcond patterns,
>> which would allow me to get rid of conversions that I need to put all
>> over the code.
>>
>> Also at the moment the patch breaks lto frontend with a simple example:
>> #define vector(elcount, type)  \
>> __attribute__((vector_size((elcount)*sizeof(type)))) type
>>
>> int main (int argc, char *argv[]) {
>>    vector (4, float) f0;
>>    vector (4, float) f1;
>>
>>    f0 =  f1 != f0
>>          ? (vector (4, float)){-1,-1,-1,-1} : (vector (4, float)){0,0,0,0};
>>
>>    return (int)f0[argc];
>> }
>>
>> test-lto.c:8:14: internal compiler error: in convert, at lto/lto-lang.c:1244
>>
>> I looked into the file, the conversion function is defined as
>> gcc_unreachable (). I am not very familiar with lto, so I don't really
>> know what is the right way to treat the conversions.
>
> convert cannot be called from the middle-end, instead use fold_convert.

Thanks, great. I didn't know that. Using fold_convert solves my
problem and make all my tests pass.

>
>> And I seriously need help with backend patterns.
>
> I'll look at the patch in detail later today.

Thanks,
Artem.

> Richard.
>
>>
>> Thanks,
>> Artem.
>>
>
diff mbox

Patch

Index: gcc/doc/extend.texi
===================================================================
--- gcc/doc/extend.texi	(revision 177665)
+++ gcc/doc/extend.texi	(working copy)
@@ -6553,6 +6553,97 @@  invoke undefined behavior at runtime.  W
 accesses for vector subscription can be enabled with
 @option{-Warray-bounds}.
 
+In C vector comparison is supported within standard comparison operators:
+@code{==, !=, <, <=, >, >=}. Both integer-type and real-type vectors
+can be compared but only of the same type. The result of the
+comparison is a signed integer-type vector where the size of each
+element must be the same as the size of compared vectors element.
+Comparison is happening element by element. False value is 0, true
+value is -1 (constant of the appropriate type where all bits are set).
+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
+
+In addition to the vector comparison C supports conditional expressions
+where the condition is a vector of signed integers. In that case result
+of the condition is used as a mask to select either from the first 
+operand or from the second. Consider the following example:
+
+@smallexample
+typedef int v4si __attribute__ ((vector_size (16)));
+
+v4si a = @{1,2,3,4@};
+v4si b = @{3,2,1,7@};
+v4si c = @{2,3,4,5@};
+v4si d = @{6,7,8,9@};
+v4si res;
+
+res = a >= b ? c : d;  /* res would contain @{6, 3, 4, 9@}  */
+@end smallexample
+
+The number of elements in the condition must be the same as number of
+elements in the both operands. The same stands for the size of the type
+of the elements. The type of the vector conditional is determined by
+the types of the operands which must be the same. Consider an example:
+
+@smallexample
+typedef int  v4si __attribute__ ((vector_size (16)));
+typedef float v4f __attribute__ ((vector_size (16)));
+
+v4si a = @{1,2,3,4@};
+v4si b = @{2,3,4,5@};
+v4f f = @{1.,  5., 7., -8.@};
+v4f g = @{3., -2., 8.,  1.@};
+v4si ires;
+v4f fres;
+
+fres = a <= b ? f : g;  /* fres would contain @{1., 5., 7., -8.@}  */
+ires = f <= g ? a : b;  /* fres would contain @{1,  3,  3,   4@}  */
+@end smallexample
+
+For the convenience condition in the vector conditional can be just a
+vector of signed integer type. In that case this vector is implicitly
+compared with vectors of zeroes. Consider an example:
+
+@smallexample
+typedef int  v4si __attribute__ ((vector_size (16)));
+
+v4si a = @{1,0,3,0@};
+v4si b = @{2,3,4,5@};
+v4si ires;
+
+ires = a ? b : a;  /* synonym for ires = a != @{0,0,0,0@} ? a :b;  */
+@end smallexample
+
+Pleas note that the conditional where the operands are vectors and the
+condition is integer works in a standard way -- returns first operand
+if the condition is true and second otherwise. Consider an example:
+
+@smallexample
+typedef int  v4si __attribute__ ((vector_size (16)));
+
+v4si a = @{1,0,3,0@};
+v4si b = @{2,3,4,5@};
+v4si ires;
+int x,y;
+
+/* standard conditional returning A or B  */
+ires = x > y ? a : b;  
+
+/* vector conditional where the condition is (x > y ? a : b)  */
+ires = (x > y ? a : b) ? b : a; 
+@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/targhooks.h
===================================================================
--- gcc/targhooks.h	(revision 177665)
+++ gcc/targhooks.h	(working copy)
@@ -86,6 +86,7 @@  extern int default_builtin_vectorization
 extern tree default_builtin_reciprocal (unsigned int, bool, bool);
 
 extern bool default_builtin_vector_alignment_reachable (const_tree, bool);
+
 extern bool
 default_builtin_support_vector_misalignment (enum machine_mode mode,
 					     const_tree,
Index: gcc/optabs.c
===================================================================
--- gcc/optabs.c	(revision 177665)
+++ gcc/optabs.c	(working copy)
@@ -6572,16 +6572,36 @@  expand_vec_cond_expr (tree vec_cond_type
   if (icode == CODE_FOR_nothing)
     return 0;
 
-  comparison = vector_compare_rtx (op0, unsignedp, icode);
   rtx_op1 = expand_normal (op1);
   rtx_op2 = expand_normal (op2);
+  
+  if (COMPARISON_CLASS_P (op0))
+    {
+      comparison = vector_compare_rtx (op0, unsignedp, icode);
+      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));
+    }
+  else
+    {
+      rtx rtx_op0;
+      rtx vec; 
+    
+      rtx_op0 = expand_normal (op0);
+      comparison = gen_rtx_NE (mode, NULL_RTX, NULL_RTX); 
+      vec = CONST0_RTX (mode);
+
+      create_output_operand (&ops[0], target, mode);
+      create_input_operand (&ops[1], rtx_op1, mode);
+      create_input_operand (&ops[2], rtx_op2, mode);
+      create_input_operand (&ops[3], comparison, mode);
+      create_input_operand (&ops[4], rtx_op0, mode);
+      create_input_operand (&ops[5], vec, mode);
+    }
 
-  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));
   expand_insn (icode, 6, ops);
   return ops[0].value;
 }
Index: gcc/target.h
===================================================================
--- gcc/target.h	(revision 177665)
+++ gcc/target.h	(working copy)
@@ -51,6 +51,7 @@ 
 #define GCC_TARGET_H
 
 #include "insn-modes.h"
+#include "gimple.h"
 
 #ifdef ENABLE_CHECKING
 
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;
@@ -9073,26 +9082,28 @@  fold_comparison (location_t loc, enum tr
      floating-point, we can only do some of these simplifications.)  */
   if (operand_equal_p (arg0, arg1, 0))
     {
+      tree arg0_type = TREE_TYPE (arg0);
+      
       switch (code)
 	{
 	case EQ_EXPR:
-	  if (! FLOAT_TYPE_P (TREE_TYPE (arg0))
-	      || ! HONOR_NANS (TYPE_MODE (TREE_TYPE (arg0))))
+	  if (! FLOAT_TYPE_P (arg0_type)
+	      || ! HONOR_NANS (TYPE_MODE (arg0_type)))
 	    return constant_boolean_node (1, type);
 	  break;
 
 	case GE_EXPR:
 	case LE_EXPR:
-	  if (! FLOAT_TYPE_P (TREE_TYPE (arg0))
-	      || ! HONOR_NANS (TYPE_MODE (TREE_TYPE (arg0))))
+	  if (! FLOAT_TYPE_P (arg0_type)
+	      || ! HONOR_NANS (TYPE_MODE (arg0_type)))
 	    return constant_boolean_node (1, type);
 	  return fold_build2_loc (loc, EQ_EXPR, type, arg0, arg1);
 
 	case NE_EXPR:
 	  /* For NE, we can only do this simplification if integer
 	     or we don't honor IEEE floating point NaNs.  */
-	  if (FLOAT_TYPE_P (TREE_TYPE (arg0))
-	      && HONOR_NANS (TYPE_MODE (TREE_TYPE (arg0))))
+	  if (FLOAT_TYPE_P (arg0_type)
+	      && HONOR_NANS (TYPE_MODE (arg0_type)))
 	    break;
 	  /* ... fall through ...  */
 	case GT_EXPR:
Index: gcc/testsuite/gcc.c-torture/execute/vector-vcond-2.c
===================================================================
--- gcc/testsuite/gcc.c-torture/execute/vector-vcond-2.c	(revision 0)
+++ gcc/testsuite/gcc.c-torture/execute/vector-vcond-2.c	(revision 0)
@@ -0,0 +1,78 @@ 
+#define vector(elcount, type)  \
+__attribute__((vector_size((elcount)*sizeof(type)))) type
+
+#define vidx(type, vec, idx) (*(((type *) &(vec)) + idx))
+
+#define check_compare(count, res, i0, i1, c0, c1, op, fmt0, fmt1) \
+do { \
+    int __i; \
+    for (__i = 0; __i < count; __i ++) { \
+        if ((res)[__i] != \
+                ((i0)[__i] op (i1)[__i]  \
+		? (c0)[__i] : (c1)[__i]))  \
+	{ \
+            __builtin_printf (fmt0 " != (" fmt1 " " #op " " fmt1 " ? " \
+			      fmt0 " : " fmt0 ")", \
+	    (res)[__i], (i0)[__i], (i1)[__i],\
+	    (c0)[__i], (c1)[__i]); \
+            __builtin_abort (); \
+        } \
+    } \
+} while (0)
+
+#define test(count, v0, v1, c0, c1, res, fmt0, fmt1); \
+do { \
+    res = (v0 > v1) ? c0: c1; \
+    check_compare (count, res, v0, v1, c0, c1, >, fmt0, fmt1); \
+    res = (v0 >= v1) ? c0: c1; \
+    check_compare (count, res, v0, v1, c0, c1, >=, fmt0, fmt1); \
+    res = (v0 < v1) ? c0: c1; \
+    check_compare (count, res, v0, v1, c0, c1, <, fmt0, fmt1); \
+    res = (v0 <= v1) ? c0: c1; \
+    check_compare (count, res, v0, v1, c0, c1, <=, fmt0, fmt1); \
+    res = (v0 == v1) ? c0: c1; \
+    check_compare (count, res, v0, v1, c0, c1, ==, fmt0, fmt1); \
+    res = (v0 != v1) ? c0: c1; \
+    check_compare (count, res, v0, v1, c0, c1, !=, fmt0, fmt1); \
+} while (0)
+
+
+int main (int argc, char *argv[]) {
+  vector (4, int) i0 = {argc, 1,  2,  10}; 
+  vector (4, int) i1 = {0, argc, 2, (int)-23};
+  vector (4, int) ires;
+  vector (4, float) f0 = {1., 7., (float)argc, 4.};
+  vector (4, float) f1 = {6., 2., 8., (float)argc};
+  vector (4, float) fres;
+
+  vector (2, double) d0 = {1., (double)argc};
+  vector (2, double) d1 = {6., 2.};
+  vector (2, double) dres;
+  vector (2, long) l0 = {argc, 3};
+  vector (2, long) l1 = {5,  8};
+  vector (2, long) lres;
+  
+  /* Thes tests work fine.  */
+  test (4, i0, i1, f0, f1, fres, "%f", "%i");
+  test (4, f0, f1, i0, i1, ires, "%i", "%f");
+  test (2, d0, d1, l0, l1, lres, "%i", "%f");
+  test (2, l0, l1, d0, d1, dres, "%f", "%i");
+
+  /* Condition expressed with a single variable.  */
+  dres = l0 ? d0 : d1;
+  check_compare (2, dres, l0, ((vector (2, long)){0, 0}), d0, d1, !=, "%f", "%i");
+  
+  lres = l1 ? l0 : l1;
+  check_compare (2, lres, l1, ((vector (2, long)){0, 0}), l0, l1, !=, "%i", "%i");
+ 
+  fres = i0 ? f0 : f1;
+  check_compare (4, fres, i0, ((vector (4, int)){0, 0, 0, 0}), 
+		 f0, f1, !=, "%f", "%i");
+
+  ires = i1 ? i0 : i1;
+  check_compare (4, ires, i1, ((vector (4, int)){0, 0, 0, 0}), 
+		 i0, i1, !=, "%i", "%i");
+
+  return 0;
+}
+
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-vcond-1.c
===================================================================
--- gcc/testsuite/gcc.c-torture/execute/vector-vcond-1.c	(revision 0)
+++ gcc/testsuite/gcc.c-torture/execute/vector-vcond-1.c	(revision 0)
@@ -0,0 +1,154 @@ 
+#define vector(elcount, type)  \
+__attribute__((vector_size((elcount)*sizeof(type)))) type
+
+#define vidx(type, vec, idx) (*(((type *) &(vec)) + idx))
+
+#define check_compare(type, count, res, i0, i1, c0, c1, op, fmt) \
+do { \
+    int __i; \
+    for (__i = 0; __i < count; __i ++) { \
+        if (vidx (type, res, __i) != \
+                ((vidx (type, i0, __i) op vidx (type, i1, __i))  \
+		? vidx (type, c0, __i) : vidx (type, c1, __i)))  \
+	{ \
+            __builtin_printf (fmt " != ((" fmt " " #op " " fmt ") ? " fmt " : " fmt ")", \
+	    vidx (type, res, __i), vidx (type, i0, __i), vidx (type, i1, __i),\
+	    vidx (type, c0, __i), vidx (type, c1, __i)); \
+            __builtin_abort (); \
+        } \
+    } \
+} while (0)
+
+#define test(type, count, v0, v1, c0, c1, res, fmt); \
+do { \
+    res = (v0 > v1) ? c0: c1; \
+    check_compare (type, count, res, v0, v1, c0, c1, >, fmt); \
+    res = (v0 >= v1) ? c0: c1; \
+    check_compare (type, count, res, v0, v1, c0, c1, >=, fmt); \
+    res = (v0 < v1) ? c0: c1; \
+    check_compare (type, count, res, v0, v1, c0, c1, <, fmt); \
+    res = (v0 <= v1) ? c0: c1; \
+    check_compare (type, count, res, v0, v1, c0, c1, <=, fmt); \
+    res = (v0 == v1) ? c0: c1; \
+    check_compare (type, count, res, v0, v1, c0, c1, ==, fmt); \
+    res = (v0 != v1) ? c0: c1; \
+    check_compare (type, count, res, v0, v1, c0, c1, !=, fmt); \
+} while (0)
+
+int main (int argc, char *argv[]) {
+#define INT  int
+    vector (4, INT) i0; vector (4, INT) i1;
+    vector (4, INT) ic0; vector (4, INT) ic1;
+    vector (4, INT) ires;
+
+    i0 = (vector (4, INT)){argc, 1,  2,  10};
+    i1 = (vector (4, INT)){0, 3, 2, (INT)-23};    
+    
+    ic0 = (vector (4, INT)){1, argc,  argc,  10};
+    ic1 = (vector (4, INT)){2, 3, argc, (INT)-23};    
+    test (INT, 4, i0, i1, ic0, ic1, ires, "%i");
+#undef INT
+
+#define INT  unsigned int
+    vector (4, INT) ui0; vector (4, INT) ui1;
+    vector (4, INT) uic0; vector (4, INT) uic1;
+    vector (4, INT) uires;
+
+    ui0 = (vector (4, INT)){argc, 1,  2,  10};
+    ui1 = (vector (4, INT)){0, 3, 2, (INT)-23};    
+    
+    uic0 = (vector (4, INT)){1, argc,  argc,  10};
+    uic1 = (vector (4, INT)){2, 3, argc, (INT)-23};    
+    test (INT, 4, ui0, ui1, uic0, uic1, uires, "%u");
+#undef INT
+
+#define SHORT short
+    vector (8, SHORT) s0;   vector (8, SHORT) s1;
+    vector (8, SHORT) sc0;   vector (8, SHORT) sc1;
+    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};
+    
+    sc0 = (vector (8, SHORT)){argc, 1,  argc,  10,  6, 87, (SHORT)-5, argc};
+    sc1= (vector (8, SHORT)){0, 5, 2, (SHORT)-23, 2, 10, (SHORT)-2, argc};
+
+    test (SHORT, 8, s0, s1, sc0, sc1, sres, "%i");
+#undef SHORT
+
+#define SHORT unsigned short
+    vector (8, SHORT) us0;   vector (8, SHORT) us1;
+    vector (8, SHORT) usc0;   vector (8, SHORT) usc1;
+    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};
+    
+    usc0 = (vector (8, SHORT)){argc, 1,  argc,  10,  6, 87, (SHORT)-5, argc};
+    usc1= (vector (8, SHORT)){0, 5, 2, (SHORT)-23, 2, 10, (SHORT)-2, argc};
+
+    test (SHORT, 8, us0, us1, usc0, usc1, usres, "%u");
+#undef SHORT
+
+#define CHAR signed char
+    vector (16, CHAR) c0;   vector (16, CHAR) c1;
+    vector (16, CHAR) cc0;   vector (16, CHAR) cc1;
+    vector (16, CHAR) cres;
+
+    c0 = (vector (16, CHAR)){argc, 1,  2,  4,  7, 87, (CHAR)-5, 2, \
+                             argc, 1,  3,  18,  6, 87, (CHAR)-5, 2 };
+
+    c1 = (vector (16, CHAR)){0, 3, 2, (CHAR)-23, 12, 10, (CHAR)-2, 0, \
+                             0, 3, 2, (CHAR)-5, 28, 10, (CHAR)-2, 0};
+    
+    cc0 = (vector (16, CHAR)){argc, 1,  argc,  4,  7, 87, (CHAR)-23, 2, \
+                             33, 8,  3,  18,  6, 87, (CHAR)-5, 41 };
+
+    cc1 = (vector (16, CHAR)){0, 27, 2, (CHAR)-1, 12, 10, (CHAR)-2, 0, \
+                             0, 3, 0x23, (CHAR)-5, 28, 1, (CHAR)-2, 0};
+
+    test (CHAR, 16, c0, c1, cc0, cc1, cres, "%i");
+#undef CHAR
+
+#define CHAR unsigned char
+    vector (16, CHAR) uc0;   vector (16, CHAR) uc1;
+    vector (16, CHAR) ucc0;   vector (16, CHAR) ucc1;
+    vector (16, CHAR) ucres;
+
+    uc0 = (vector (16, CHAR)){argc, 1,  2,  4,  7, 87, (CHAR)-5, 2, \
+                             argc, 1,  3,  18,  6, 87, (CHAR)-5, 2 };
+
+    uc1 = (vector (16, CHAR)){0, 3, 2, (CHAR)-23, 12, 10, (CHAR)-2, 0, \
+                             0, 3, 2, (CHAR)-5, 28, 10, (CHAR)-2, 0};
+    
+    ucc0 = (vector (16, CHAR)){argc, 1,  argc,  4,  7, 87, (CHAR)-23, 2, \
+                             33, 8,  3,  18,  6, 87, (CHAR)-5, 41 };
+
+    ucc1 = (vector (16, CHAR)){0, 27, 2, (CHAR)-1, 12, 10, (CHAR)-2, 0, \
+                             0, 3, 0x23, (CHAR)-5, 28, 1, (CHAR)-2, 0};
+
+    test (CHAR, 16, uc0, uc1, ucc0, ucc1, ucres, "%u");
+#undef CHAR
+
+/* Float version.  */
+   vector (4, float) f0 = {1., 7., (float)argc, 4.};
+   vector (4, float) f1 = {6., 2., 8., (float)argc};
+   vector (4, float) fc0 = {3., 12., 4., (float)argc};
+   vector (4, float) fc1 = {7., 5., (float)argc, 6.};
+   vector (4, float) fres;
+
+   test (float, 4, f0, f1, fc0, fc1, fres, "%f");
+
+/* Double version.  */
+   vector (2, double) d0 = {1., (double)argc};
+   vector (2, double) d1 = {6., 2.};
+   vector (2, double) dc0 = {(double)argc, 7.};
+   vector (2, double) dc1 = {7., 5.};
+   vector (2, double) dres;
+
+   //test (double, 2, d0, d1, dc0, dc1, dres, "%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,24 @@ 
+/* { 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" } */
+
+  r4 ? y : p4;	    /* { dg-error "vectors of different types involved in vector comparison" } */
+  r4 ? r4 : r8;	    /* { dg-error "vectors of different length found in vector comparison" } */
+  y ? f4 : y;	    /* { dg-error "non-integer type in vector condition" } */
+  
+  /* Do not trigger that  */
+  q4 ? p4 : r4;	    /* { "vector comparison must be of signed integer vector type" } */
+}
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,27 @@ 
+/* { 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;
+
+vec 
+foo (int x)
+{
+  return (x ? i : j) ? a : b;
+}
+
+vec 
+bar (int x)
+{
+  return a ? (x ? i : j) : b;
+}
+
+vec 
+baz (int x)
+{
+  return a ? b : (x ? i : j);
+}
Index: gcc/expr.c
===================================================================
--- gcc/expr.c	(revision 177665)
+++ gcc/expr.c	(working copy)
@@ -8440,6 +8440,37 @@  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 arg_type = TREE_TYPE (arg0);
+	  tree el_type = TREE_TYPE (arg_type);
+	  tree t, ifexp, if_true, if_false;
+	  
+	  el_type = lang_hooks.types.type_for_size (TYPE_PRECISION (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));
+	  
+	  if (arg_type != type)
+	    {
+	      if_true = convert (arg_type, if_true);
+	      if_false = convert (arg_type, if_false);
+	      t = build3 (VEC_COND_EXPR, arg_type, ifexp, if_true, if_false);
+	      t = convert (type, t);
+	    }
+	  else
+	    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)
@@ -4009,6 +4009,66 @@  ep_convert_and_check (tree type, tree ex
   return convert (type, expr);
 }
 
+static tree
+fold_build_vec_cond_expr (tree ifexp, tree op1, tree op2)
+{
+  bool wrap = true;
+  bool maybe_const = false;
+  bool need_convert = false;
+  tree vcond, tmp;
+  tree res_type = TREE_TYPE (op1);
+
+  if (! COMPARISON_CLASS_P (ifexp))
+    {
+      tree intt, rt;
+
+      intt = c_common_type_for_size (TYPE_PRECISION (TREE_TYPE (res_type)),0);
+      rt = build_vector_type (intt, TYPE_VECTOR_SUBPARTS (res_type));
+
+      ifexp = build2 (NE_EXPR, rt, ifexp, 
+		      build_vector_from_val (rt, build_int_cst (intt, 0)));
+    }
+  
+  /* Currently the expansion of VEC_COND_EXPR does not allow
+     expessions where the type of vectors you compare differs
+     form the type of vectors you select from. For the time
+     being we insert implicit conversions.  */
+  if (TREE_TYPE (ifexp) != res_type)
+    {
+      tree comp_type = TREE_TYPE (ifexp);
+      
+      op1 = convert (comp_type, op1);
+      op2 = convert (comp_type, op2);
+      vcond = build3 (VEC_COND_EXPR, comp_type, ifexp, op1, op2);
+      need_convert = true;
+    }
+  else
+    vcond = build3 (VEC_COND_EXPR, TREE_TYPE (op1), ifexp, op1, op2);
+
+  
+  /* Avoid C_MAYBE_CONST in VEC_COND_EXPR.  */
+  
+  tmp = c_fully_fold (TREE_OPERAND (vcond, 0), false, &maybe_const);
+  TREE_OPERAND (vcond, 0) = save_expr (tmp);
+  wrap &= maybe_const;
+  
+  tmp = c_fully_fold (TREE_OPERAND (vcond, 1), false, &maybe_const);
+  TREE_OPERAND (vcond, 1) = save_expr (tmp);
+  wrap &= maybe_const;
+
+  tmp = c_fully_fold (TREE_OPERAND (vcond, 2), false, &maybe_const);
+  TREE_OPERAND (vcond, 2) = save_expr (tmp);
+  wrap &= maybe_const;
+
+  if (!wrap)
+    vcond = c_wrap_maybe_const (vcond, true);
+  
+  if (need_convert)
+    vcond = convert (res_type, vcond);
+
+  return vcond;
+}
+
 /* Build and return a conditional expression IFEXP ? OP1 : OP2.  If
    IFEXP_BCP then the condition is a call to __builtin_constant_p, and
    if folded to an integer constant then the unselected half may
@@ -4058,6 +4118,49 @@  build_conditional_expr (location_t colon
   type2 = TREE_TYPE (op2);
   code2 = TREE_CODE (type2);
 
+  if (TREE_CODE (TREE_TYPE (ifexp)) == VECTOR_TYPE)
+    {
+      if (TREE_CODE (type1) != VECTOR_TYPE
+	  || TREE_CODE (type2) != VECTOR_TYPE)
+        {
+          error_at (colon_loc, "vector comparison arguments must be of "
+                               "type vector");
+          return error_mark_node;
+        }
+
+      if (TREE_CODE (TREE_TYPE (TREE_TYPE (ifexp))) != INTEGER_TYPE)
+        {
+          error_at (colon_loc, "non-integer type in vector condition");
+          return error_mark_node;
+        }
+      
+      if (TYPE_VECTOR_SUBPARTS (type1) != TYPE_VECTOR_SUBPARTS (type2)
+          || TYPE_VECTOR_SUBPARTS (TREE_TYPE (ifexp))
+             != TYPE_VECTOR_SUBPARTS (type1))
+        {
+          error_at (colon_loc, "vectors of different length found in "
+                               "vector comparison");
+          return error_mark_node;
+        }
+      
+      if (TREE_TYPE (type1) != TREE_TYPE (type2))
+        {
+          error_at (colon_loc, "vectors of different types involved in "
+                               "vector comparison");
+          return error_mark_node;
+        }
+
+      if (TYPE_SIZE (TREE_TYPE (TREE_TYPE (ifexp))) 
+          != TYPE_SIZE (TREE_TYPE (type1)))
+        {
+          error_at (colon_loc, "vector-condition element type must be "
+                               "the same as result vector element type");
+          return error_mark_node;
+        }
+      
+      return fold_build_vec_cond_expr (ifexp, op1, op2);
+    }
+
   /* C90 does not permit non-lvalue arrays in conditional expressions.
      In C99 they will be pointers by now.  */
   if (code1 == ARRAY_TYPE || code2 == ARRAY_TYPE)
@@ -9906,6 +10009,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 +10144,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 +10574,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)
@@ -7064,6 +7064,22 @@  gimplify_expr (tree *expr_p, gimple_seq
 	  }
 	  break;
 
+        case VEC_COND_EXPR:
+	  {
+	    enum gimplify_status r0, r1, r2;
+
+	    r0 = gimplify_expr (&TREE_OPERAND (*expr_p, 0), pre_p,
+				post_p, is_gimple_condexpr, fb_rvalue);
+	    r1 = gimplify_expr (&TREE_OPERAND (*expr_p, 1), pre_p,
+				post_p, is_gimple_val, fb_rvalue);
+	    r2 = gimplify_expr (&TREE_OPERAND (*expr_p, 2), pre_p,
+				post_p, is_gimple_val, fb_rvalue);
+	    recalculate_side_effects (*expr_p);
+
+	    ret = MIN (r0, MIN (r1, r2));
+	  }
+	  break;
+
 	case TARGET_MEM_REF:
 	  {
 	    enum gimplify_status r0 = GS_ALL_DONE, r1 = GS_ALL_DONE;
@@ -7348,6 +7364,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)
@@ -30,11 +30,16 @@  along with GCC; see the file COPYING3.
 #include "tree-pass.h"
 #include "flags.h"
 #include "ggc.h"
+#include "target.h"
 
 /* Need to include rtl.h, expr.h, etc. for optabs.  */
 #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 +130,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 cond;
+  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 = lang_hooks.types.type_for_size (TYPE_PRECISION (inner_type), 0);
+
+  cond = gimplify_build2 (gsi, code, comp_type, a, b);
+  return gimplify_build3 (gsi, COND_EXPR, comp_type, cond, 
+                    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 +363,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 (type, TYPE_MODE (type)))
+    t = expand_vector_piecewise (gsi, do_compare, type, 
+                    TREE_TYPE (TREE_TYPE (op0)), op0, op1, code);
+  else
+    t = gimplify_build2  (gsi, code, type, op0, op1);
+
+  return t;
+}
+
 static tree
 expand_vector_operation (gimple_stmt_iterator *gsi, tree type, tree compute_type,
 			 gimple assign, enum tree_code code)
@@ -375,8 +423,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;
       }
@@ -432,6 +499,126 @@  type_for_widest_vector_mode (enum machin
     }
 }
 
+
+
+/* Expand vector condition EXP which should have the form
+   VEC_COND_EXPR<cond, vec0, vec1> into the following
+   vector:
+     {cond[i] != 0 ? vec0[i] : vec1[i], ... }
+   i changes from 0 to TYPE_VECTOR_SUBPARTS (TREE_TYPE (vec0)).  */
+static tree
+expand_vec_cond_expr_piecewise (gimple_stmt_iterator *gsi, tree exp)
+{
+  tree cond = TREE_OPERAND (exp, 0);
+  tree vec0 = TREE_OPERAND (exp, 1);
+  tree vec1 = TREE_OPERAND (exp, 2);
+  tree type = TREE_TYPE (vec0);
+  tree lhs, rhs, notmask;
+  tree var, new_rhs;
+  optab op = NULL;
+  gimple new_stmt;
+  gimple_stmt_iterator gsi_tmp;
+  tree t;
+
+  
+  if (COMPARISON_CLASS_P (cond))
+    {
+      /* Expand vector condition inside of VEC_COND_EXPR.  */
+      if (! expand_vec_cond_expr_p (TREE_TYPE (cond), 
+				    TYPE_MODE (TREE_TYPE (cond))))
+	{
+	  tree op0 = TREE_OPERAND (cond, 0);
+	  tree op1 = TREE_OPERAND (cond, 1);
+
+	  var = create_tmp_reg (TREE_TYPE (cond), "cond");
+	  new_rhs = expand_vector_piecewise (gsi, do_compare, 
+					     TREE_TYPE (cond),
+					     TREE_TYPE (TREE_TYPE (op1)),
+					     op0, op1, TREE_CODE (cond));
+
+	  new_stmt = gimple_build_assign (var, new_rhs);
+	  gsi_insert_before (gsi, new_stmt, GSI_SAME_STMT);
+	  update_stmt (gsi_stmt (*gsi));
+	}
+      else
+	var = cond;
+    }
+  else
+    var = cond;
+  
+  gsi_tmp = *gsi;
+  gsi_prev (&gsi_tmp);
+
+  /* Expand VCOND<mask, v0, v1> to ((v0 & mask) | (v1 & ~mask))  */
+  lhs = gimplify_build2 (gsi, BIT_AND_EXPR, type, var, vec0);
+  notmask = gimplify_build1 (gsi, BIT_NOT_EXPR, type, var);
+  rhs = gimplify_build2 (gsi, BIT_AND_EXPR, type, notmask, vec1);
+  t = gimplify_build2 (gsi, BIT_IOR_EXPR, type, lhs, rhs);
+
+  /* Run vecower on the expresisons we have introduced.  */
+  for (; gsi_tmp.ptr != gsi->ptr; gsi_next (&gsi_tmp))
+    expand_vector_operations_1 (&gsi_tmp);
+  
+  return t;
+}
+
+static bool
+is_vector_comparison (gimple_stmt_iterator *gsi, tree expr)
+{
+  tree type = TREE_TYPE (expr);
+
+  if (TREE_CODE (expr) == VEC_COND_EXPR)
+    return true;
+    
+  if (COMPARISON_CLASS_P (expr) && TREE_CODE (type) == VECTOR_TYPE)
+    return true;
+
+  if (TREE_CODE (expr) == BIT_IOR_EXPR || TREE_CODE (expr) == BIT_AND_EXPR
+      || TREE_CODE (expr) == BIT_XOR_EXPR)
+    return is_vector_comparison (gsi, TREE_OPERAND (expr, 0))
+	   & is_vector_comparison (gsi, TREE_OPERAND (expr, 1));
+
+  if (TREE_CODE (expr) == VAR_DECL)
+    { 
+      gimple_stmt_iterator gsi_tmp;
+      tree name = DECL_NAME (expr);
+      tree var = NULL_TREE;
+      
+      gsi_tmp = *gsi;
+
+      for (; gsi_tmp.ptr; gsi_prev (&gsi_tmp))
+	{
+	  gimple stmt = gsi_stmt (gsi_tmp);
+
+	  if (gimple_code (stmt) != GIMPLE_ASSIGN)
+	    continue;
+
+	  if (TREE_CODE (gimple_assign_lhs (stmt)) == VAR_DECL
+	      && DECL_NAME (gimple_assign_lhs (stmt)) == name)
+	    return is_vector_comparison (&gsi_tmp, 
+					 gimple_assign_rhs_to_tree (stmt));
+	}
+    } 
+  
+  if (TREE_CODE (expr) == SSA_NAME)
+    {
+      enum tree_code code;
+      gimple exprdef = SSA_NAME_DEF_STMT (expr);
+
+      if (gimple_code (exprdef) != GIMPLE_ASSIGN)
+	return false;
+
+      if (TREE_CODE (gimple_expr_type (exprdef)) != VECTOR_TYPE)
+	return false;
+
+      
+      return is_vector_comparison (gsi, 
+				   gimple_assign_rhs_to_tree (exprdef));
+    }
+
+  return false;
+}
+
 /* Process one statement.  If we identify a vector operation, expand it.  */
 
 static void
@@ -450,11 +637,41 @@  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 (code == VEC_COND_EXPR)
+    {
+      tree exp = gimple_assign_rhs1 (stmt);
+      tree cond = TREE_OPERAND (exp, 0);
+      
+      /* Try to get rid from the useless vector comparison 
+	 x != {0,0,...} which is inserted by the typechecker.  */
+      if (COMPARISON_CLASS_P (cond) && TREE_CODE (cond) == NE_EXPR)
+	{
+	  tree el = uniform_vector_p (TREE_OPERAND (cond, 1));
+	  
+	  if (el != NULL_TREE && TREE_CONSTANT (el) 
+	      && TREE_CODE (TREE_TYPE (el)) == INTEGER_TYPE
+	      && tree_low_cst (el, 0) == 0
+	      && is_vector_comparison (gsi, TREE_OPERAND (cond, 0)))
+	    cond = TREE_OPERAND (cond, 0);
+	}
+      
+      if (expand_vec_cond_expr_p (TREE_TYPE (exp), 
+                                  TYPE_MODE (TREE_TYPE (exp))))
+        {
+	  update_stmt (gsi_stmt (*gsi));
+	  return;
+        }
+        
+      new_rhs = expand_vec_cond_expr_piecewise (gsi, exp);
+      gimple_assign_set_rhs_from_tree (gsi, new_rhs);
+      update_stmt (gsi_stmt (*gsi));
+    }
 
   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)
Index: gcc/Makefile.in
===================================================================
--- gcc/Makefile.in	(revision 177665)
+++ gcc/Makefile.in	(working copy)
@@ -888,7 +888,7 @@  EXCEPT_H = except.h $(HASHTAB_H) vecprim
 TARGET_DEF = target.def target-hooks-macros.h
 C_TARGET_DEF = c-family/c-target.def target-hooks-macros.h
 COMMON_TARGET_DEF = common/common-target.def target-hooks-macros.h
-TARGET_H = $(TM_H) target.h $(TARGET_DEF) insn-modes.h
+TGT = $(TM_H) target.h $(TARGET_DEF) insn-modes.h
 C_TARGET_H = c-family/c-target.h $(C_TARGET_DEF)
 COMMON_TARGET_H = common/common-target.h $(INPUT_H) $(COMMON_TARGET_DEF)
 MACHMODE_H = machmode.h mode-classes.def insn-modes.h
@@ -919,8 +919,9 @@  TREE_H = tree.h all-tree.def tree.def c-
 REGSET_H = regset.h $(BITMAP_H) hard-reg-set.h
 BASIC_BLOCK_H = basic-block.h $(PREDICT_H) $(VEC_H) $(FUNCTION_H) cfghooks.h
 GIMPLE_H = gimple.h gimple.def gsstruct.def pointer-set.h $(VEC_H) \
-	vecir.h $(GGC_H) $(BASIC_BLOCK_H) $(TARGET_H) tree-ssa-operands.h \
+	vecir.h $(GGC_H) $(BASIC_BLOCK_H) $(TGT) tree-ssa-operands.h \
 	tree-ssa-alias.h $(INTERNAL_FN_H)
+TARGET_H = $(TGT) gimple.h
 GCOV_IO_H = gcov-io.h gcov-iov.h auto-host.h
 COVERAGE_H = coverage.h $(GCOV_IO_H)
 DEMANGLE_H = $(srcdir)/../include/demangle.h
@@ -3185,7 +3186,7 @@  tree-vect-generic.o : tree-vect-generic.
     $(TM_H) $(TREE_FLOW_H) $(GIMPLE_H) tree-iterator.h $(TREE_PASS_H) \
     $(FLAGS_H) $(OPTABS_H) $(MACHMODE_H) $(EXPR_H) \
     langhooks.h $(FLAGS_H) $(DIAGNOSTIC_H) gt-tree-vect-generic.h $(GGC_H) \
-    coretypes.h insn-codes.h
+    coretypes.h insn-codes.h target.h
 df-core.o : df-core.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \
    insn-config.h $(RECOG_H) $(FUNCTION_H) $(REGS_H) alloc-pool.h \
    hard-reg-set.h $(BASIC_BLOCK_H) $(DF_H) $(BITMAP_H) sbitmap.h $(TIMEVAR_H) \
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/c-parser.c
===================================================================
--- gcc/c-parser.c	(revision 177665)
+++ gcc/c-parser.c	(working copy)
@@ -5339,6 +5339,15 @@  c_parser_conditional_expression (c_parse
       tree eptype = NULL_TREE;
 
       middle_loc = c_parser_peek_token (parser)->location;
+
+      if (TREE_CODE (TREE_TYPE (cond.value)) == VECTOR_TYPE)
+        {
+          error_at (middle_loc, "cannot ommit middle operator in "
+                                "vector comparison");
+          ret.value = error_mark_node;
+          return ret;
+        }
+      
       pedwarn (middle_loc, OPT_pedantic, 
 	       "ISO C forbids omitting the middle term of a ?: expression");
       warn_for_omitted_condop (middle_loc, cond.value);
@@ -5357,9 +5366,12 @@  c_parser_conditional_expression (c_parse
     }
   else
     {
-      cond.value
-	= c_objc_common_truthvalue_conversion
-	(cond_loc, default_conversion (cond.value));
+      if (TREE_CODE (TREE_TYPE (cond.value)) != VECTOR_TYPE)
+        {
+          cond.value
+            = c_objc_common_truthvalue_conversion
+            (cond_loc, default_conversion (cond.value));
+        }
       c_inhibit_evaluation_warnings += cond.value == truthvalue_false_node;
       exp1 = c_parser_expression_conv (parser);
       mark_exp_read (exp1.value);
Index: gcc/config/i386/i386.c
===================================================================
--- gcc/config/i386/i386.c	(revision 177665)
+++ gcc/config/i386/i386.c	(working copy)
@@ -25,6 +25,7 @@  along with GCC; see the file COPYING3.
 #include "tm.h"
 #include "rtl.h"
 #include "tree.h"
+#include "tree-flow.h"
 #include "tm_p.h"
 #include "regs.h"
 #include "hard-reg-set.h"
@@ -18402,27 +18403,55 @@  ix86_expand_sse_fp_minmax (rtx dest, enu
   return true;
 }
 
+rtx rtx_build_vector_from_val (enum machine_mode, HOST_WIDE_INT);
+
+/* Returns a vector of mode MODE where all the elements are ARG.  */
+rtx
+rtx_build_vector_from_val (enum machine_mode mode, HOST_WIDE_INT arg)
+{
+  rtvec v;
+  int units, i;
+  enum machine_mode inner;
+  
+  units = GET_MODE_NUNITS (mode);
+  inner = GET_MODE_INNER (mode);
+  v = rtvec_alloc (units);
+  for (i = 0; i < units; ++i)
+    RTVEC_ELT (v, i) = gen_rtx_CONST_INT (inner, arg);
+  
+  return gen_rtx_raw_CONST_VECTOR (mode, v);
+}
+
 /* Expand an sse vector comparison.  Return the register with the result.  */
 
 static rtx
 ix86_expand_sse_cmp (rtx dest, enum rtx_code code, rtx cmp_op0, rtx cmp_op1,
-		     rtx op_true, rtx op_false)
+		     rtx op_true, rtx op_false, bool no_comparison)
 {
   enum machine_mode mode = GET_MODE (dest);
   rtx x;
 
-  cmp_op0 = force_reg (mode, cmp_op0);
-  if (!nonimmediate_operand (cmp_op1, mode))
-    cmp_op1 = force_reg (mode, cmp_op1);
+  /* Avoid useless comparison.  */
+  if (no_comparison)
+    {
+      cmp_op0 = force_reg (mode, cmp_op0);
+      x = cmp_op0;
+    }
+  else
+    {
+      cmp_op0 = force_reg (mode, cmp_op0);
+      if (!nonimmediate_operand (cmp_op1, mode))
+	cmp_op1 = force_reg (mode, cmp_op1);
+
+      x = gen_rtx_fmt_ee (code, mode, cmp_op0, cmp_op1);
+    }
 
   if (optimize
       || reg_overlap_mentioned_p (dest, op_true)
       || reg_overlap_mentioned_p (dest, op_false))
     dest = gen_reg_rtx (mode);
 
-  x = gen_rtx_fmt_ee (code, mode, cmp_op0, cmp_op1);
   emit_insn (gen_rtx_SET (VOIDmode, dest, x));
-
   return dest;
 }
 
@@ -18434,8 +18463,14 @@  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))
+  rtx mask_true;
+  
+  if (rtx_equal_p (op_true, rtx_build_vector_from_val (mode, -1))
+      && 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);
@@ -18512,7 +18547,7 @@  ix86_expand_fp_movcc (rtx operands[])
 	return true;
 
       tmp = ix86_expand_sse_cmp (operands[0], code, op0, op1,
-				 operands[2], operands[3]);
+				 operands[2], operands[3], false);
       ix86_expand_sse_movcc (operands[0], tmp, operands[2], operands[3]);
       return true;
     }
@@ -18555,7 +18590,7 @@  ix86_expand_fp_vcond (rtx operands[])
     return true;
 
   cmp = ix86_expand_sse_cmp (operands[0], code, operands[4], operands[5],
-			     operands[1], operands[2]);
+			     operands[1], operands[2], false);
   ix86_expand_sse_movcc (operands[0], cmp, operands[1], operands[2]);
   return true;
 }
@@ -18569,12 +18604,27 @@  ix86_expand_int_vcond (rtx operands[])
   enum rtx_code code = GET_CODE (operands[3]);
   bool negate = false;
   rtx x, cop0, cop1;
+  rtx comp, cond0, cond1;
+  bool single_var = false;
 
+  comp = operands[3];
   cop0 = operands[4];
   cop1 = operands[5];
 
+  /* If we have a single-variable vcond, the second comparison
+     operand is {0,0...}. Replace it with CONST0_RTX, in order
+     to get some more optimisations later.  */
+  if (GET_CODE (comp) == NE && XEXP (comp, 0) == NULL_RTX 
+      && XEXP (comp, 1) == NULL_RTX)
+    {
+      cond0 = cop0;
+      cond1 = CONST0_RTX (mode);
+      single_var = true;
+    }
+
+
   /* XOP supports all of the comparisons on all vector int types.  */
-  if (!TARGET_XOP)
+  if (!TARGET_XOP && !single_var)
     {
       /* Canonicalize the comparison to EQ, GT, GTU.  */
       switch (code)
@@ -18681,8 +18731,16 @@  ix86_expand_int_vcond (rtx operands[])
 	}
     }
 
-  x = ix86_expand_sse_cmp (operands[0], code, cop0, cop1,
-			   operands[1+negate], operands[2-negate]);
+  if (single_var)
+    {
+      x = ix86_expand_sse_cmp (operands[0], code, cond0, cond1,
+			       operands[1+negate], operands[2-negate], true);
+    }
+  else
+    {
+      x = ix86_expand_sse_cmp (operands[0], code, cop0, cop1,
+			       operands[1+negate], operands[2-negate], false);
+    }
 
   ix86_expand_sse_movcc (operands[0], x, operands[1+negate],
 			 operands[2-negate]);
@@ -18774,7 +18832,7 @@  ix86_expand_sse_unpack (rtx operands[2],
 	tmp = force_reg (imode, CONST0_RTX (imode));
       else
 	tmp = ix86_expand_sse_cmp (gen_reg_rtx (imode), GT, CONST0_RTX (imode),
-				   operands[1], pc_rtx, pc_rtx);
+				   operands[1], pc_rtx, pc_rtx, false);
 
       emit_insn (unpack (dest, operands[1], tmp));
     }