diff mbox

vector comparisons in C++

Message ID alpine.DEB.2.02.1209141534590.5985@stedding.saclay.inria.fr
State New
Headers show

Commit Message

Marc Glisse Sept. 14, 2012, 1:59 p.m. UTC
Here is the patch I just tested. Changes compared to the previous patch 
include:

* same_type_ignoring_top_level_qualifiers_p
* build_vector_type: don't use an opaque vector for the return type of
   operator< (not sure what the point was of making it opaque?)
* Disable BIT_AND -> TRUTH_AND optimization for vectors
* Disable (type)(a<b) -> (a<b)?type(true):type(false) for vectors.
   It would be doable with vec_cond_expr, but I am not sure it helps.
* In a<b|a==b -> a<=b, use a vector type, not boolean
* 2 more testcases (through which I discovered the issues)

I am sure there are other optimizations that do weird things, but I should 
stop increasing the size of this patch... I'll update the doc in a later 
patch.

Ok?

2012-09-14  Marc Glisse  <marc.glisse@inria.fr>
         PR c++/54427

gcc/ChangeLog
 	* fold-const.c (fold_unary_loc): Disable for VECTOR_TYPE.
 	(fold_binary_loc): Likewise.
 	* gimple-fold.c (and_comparisons_1): Handle VECTOR_TYPE.
 	(or_comparisons_1): Likewise.

gcc/cp/ChangeLog
         * typeck.c (cp_build_binary_op) [LSHIFT_EXPR, RSHIFT_EXPR, EQ_EXPR,
         NE_EXPR, LE_EXPR, GE_EXPR, LT_EXPR, GT_EXPR]: Handle VECTOR_TYPE.

gcc/testsuite/ChangeLog
 	* g++.dg/other/vector-compare.C: New testcase.
 	* gcc/testsuite/c-c++-common/vector-compare-3.c: New testcase.
         * gcc.dg/vector-shift.c: Move ...
         * c-c++-common/vector-shift.c: ... here.
         * gcc.dg/vector-shift1.c: Move ...
         * c-c++-common/vector-shift1.c: ... here.
         * gcc.dg/vector-shift3.c: Move ...
         * c-c++-common/vector-shift3.c: ... here.
         * gcc.dg/vector-compare-1.c: Move ...
         * c-c++-common/vector-compare-1.c: ... here.
         * gcc.dg/vector-compare-2.c: Move ...
         * c-c++-common/vector-compare-2.c: ... here.
         * gcc.c-torture/execute/vector-compare-1.c: Move ...
         * c-c++-common/torture/vector-compare-1.c: ... here.
         * gcc.c-torture/execute/vector-compare-2.x: Delete.
         * gcc.c-torture/execute/vector-compare-2.c: Move ...
         * c-c++-common/torture/vector-compare-2.c: ... here.
         * gcc.c-torture/execute/vector-shift.c: Move ...
         * c-c++-common/torture/vector-shift.c: ... here.
         * gcc.c-torture/execute/vector-shift2.c: Move ...
         * c-c++-common/torture/vector-shift2.c: ... here.
         * gcc.c-torture/execute/vector-subscript-1.c: Move ...
         * c-c++-common/torture/vector-subscript-1.c: ... here.
         * gcc.c-torture/execute/vector-subscript-2.c: Move ...
         * c-c++-common/torture/vector-subscript-2.c: ... here.
         * gcc.c-torture/execute/vector-subscript-3.c: Move ...
         * c-c++-common/torture/vector-subscript-3.c: ... here.

Comments

Jason Merrill Sept. 14, 2012, 2:18 p.m. UTC | #1
On 09/14/2012 09:59 AM, Marc Glisse wrote:
> * build_vector_type: don't use an opaque vector for the return type of
>    operator< (not sure what the point was of making it opaque?)

I think the point was to allow conversion of the result to a different 
vector type.  Why do you want it not to be opaque?

> * Disable (type)(a<b) -> (a<b)?type(true):type(false) for vectors.
>    It would be doable with vec_cond_expr, but I am not sure it helps.

Right.  It certainly doesn't help for integer vectors.

> +	      error_at (location, "comparing vectors with different "
> +				  "element types");

Let's print the vector types in these errors.

Jason
Marc Glisse Sept. 14, 2012, 3:03 p.m. UTC | #2
On Fri, 14 Sep 2012, Jason Merrill wrote:

> On 09/14/2012 09:59 AM, Marc Glisse wrote:
>> * build_vector_type: don't use an opaque vector for the return type of
>>    operator< (not sure what the point was of making it opaque?)
>
> I think the point was to allow conversion of the result to a different vector 
> type.

Ah, I see. I'll change it back to opaque and remove that use from the 
testcase. I noticed that for the fold patch, I am using once opaque and 
once not-opaque, I'll make them both opaque, although it probably doesn't 
matter once we are out of the front-end.

> Why do you want it not to be opaque?

I wanted to use decltype(x<x) to find an integer vector type of the same 
size as x, and then actually be able to use it. Being opaque, it refuses 
to be initialized (cp/decl.c:5550). Maybe decltype (and others?) could 
return non-opaque types?

>> +	      error_at (location, "comparing vectors with different "
>> +				  "element types");
>
> Let's print the vector types in these errors.

Type is %qT right? I see a number of %q#T but can't remember where the doc 
is. Well, I'll try both and see what happens.

Thanks,
Jason Merrill Sept. 14, 2012, 4:21 p.m. UTC | #3
On 09/14/2012 11:03 AM, Marc Glisse wrote:
> I wanted to use decltype(x<x) to find an integer vector type of the same
> size as x, and then actually be able to use it. Being opaque, it refuses
> to be initialized (cp/decl.c:5550). Maybe decltype (and others?) could
> return non-opaque types?

That sounds like the right answer.

> Type is %qT right? I see a number of %q#T but can't remember where the
> doc is. Well, I'll try both and see what happens.

Either one works; the # asks for more verbose output.

Jason
diff mbox

Patch

Index: gcc/testsuite/g++.dg/other/vector-compare.C
===================================================================
--- gcc/testsuite/g++.dg/other/vector-compare.C	(revision 0)
+++ gcc/testsuite/g++.dg/other/vector-compare.C	(revision 0)
@@ -0,0 +1,38 @@ 
+/* { dg-do compile } */
+/* { dg-options "-std=gnu++11 -Wall" } */
+
+// Check that we can compare vector types that really are the same through
+// typedefs.
+
+typedef float v4f __attribute__((vector_size(4*sizeof(float))));
+
+template <class T> void eat (T&&) {}
+
+template <class T, int n>
+struct Vec
+{
+  typedef T type __attribute__((vector_size(4*sizeof(T))));
+
+  template <class U>
+  static void fun (type const& t, U& u) { eat (t > u); }
+};
+
+long long
+f (v4f *x, v4f const *y)
+{
+  return ((*x < *y) | (*x <= *y))[2];
+}
+
+int main ()
+{
+  v4f x = {0,1,2,3};
+  typedef decltype (x < x) v4i;
+  v4i y = {4,5,6,7}; // v4i is not opaque
+  Vec<const volatile float,4>::type f = {-1,5,2,3.1};
+  v4i c = (x == f) == y;
+  eat (c);
+  Vec<const volatile float,4>::fun (f, x);
+  Vec<const volatile float,4>::fun (x, f);
+  Vec<const volatile float,4>::fun (f, f);
+  Vec<const volatile float,4>::fun (x, x);
+}

Property changes on: gcc/testsuite/g++.dg/other/vector-compare.C
___________________________________________________________________
Added: svn:keywords
   + Author Date Id Revision URL
Added: svn:eol-style
   + native

Index: gcc/testsuite/c-c++-common/vector-compare-3.c
===================================================================
--- gcc/testsuite/c-c++-common/vector-compare-3.c	(revision 0)
+++ gcc/testsuite/c-c++-common/vector-compare-3.c	(revision 0)
@@ -0,0 +1,25 @@ 
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+
+typedef int v4i __attribute__((vector_size(4*sizeof(int))));
+
+// fold should not turn (vec_other)(x<y) into (x<y)?vec_other(-1):vec_other(0).
+
+void use (v4i const *z);
+
+void
+f (v4i *x, v4i *y)
+{
+  v4i const zz = *x < *y;
+  use (&zz);
+}
+
+// Optimizations shouldn't introduce a boolean type in there
+
+void
+g (v4i *x, v4i const *y, v4i *z, v4i *t)
+{
+  *z = *x < *y | *x == *y;
+  *t = *x < *y & *x > *y;
+}
+

Property changes on: gcc/testsuite/c-c++-common/vector-compare-3.c
___________________________________________________________________
Added: svn:eol-style
   + native
Added: svn:keywords
   + Author Date Id Revision URL

Index: gcc/testsuite/c-c++-common/vector-shift.c
===================================================================
--- gcc/testsuite/c-c++-common/vector-shift.c	(revision 190834)
+++ gcc/testsuite/c-c++-common/vector-shift.c	(working copy)
@@ -1,11 +1,12 @@ 
 /* { dg-do compile } */
+/* { dg-prune-output "in evaluation of" } */
 #define vector(elcount, type)  \
 __attribute__((vector_size((elcount)*sizeof(type)))) type
 
 int main (int argc, char *argv[]) {
     vector(4,char) vchar = {1,2,3,4};
     vector(4, int) vint  = {1,1,1,1};
     
     vint <<= vchar;  /* { dg-error "nvalid operands to binary <<" } */
     vchar >>= vint;  /* { dg-error "nvalid operands to binary >>" } */
 
Index: gcc/testsuite/c-c++-common/torture/vector-subscript-1.c
===================================================================
--- gcc/testsuite/c-c++-common/torture/vector-subscript-1.c	(revision 190838)
+++ gcc/testsuite/c-c++-common/torture/vector-subscript-1.c	(working copy)
@@ -1,11 +1,11 @@ 
-/* dg-do run */
+/* { dg-do run } */
 #define vector __attribute__((vector_size(sizeof(int)*4) ))
 
 /* Check to make sure that we extract and insert the vector at the same
    location for vector subscripting and that vectors layout are the same
    as arrays. */
 
 struct TV4
 {
     vector int v;
 };
Index: gcc/testsuite/c-c++-common/torture/vector-subscript-2.c
===================================================================
--- gcc/testsuite/c-c++-common/torture/vector-subscript-2.c	(revision 190838)
+++ gcc/testsuite/c-c++-common/torture/vector-subscript-2.c	(working copy)
@@ -1,10 +1,11 @@ 
+/* { dg-do run } */
 #define vector __attribute__((vector_size(sizeof(int)*4) ))
 
 /* Check to make sure that we extract and insert the vector at the same
    location for vector subscripting (with constant indexes) and
    that vectors layout are the same as arrays. */
 
 struct TV4
 {
     vector int v;
 };
Index: gcc/testsuite/c-c++-common/torture/vector-shift.c
===================================================================
--- gcc/testsuite/c-c++-common/torture/vector-shift.c	(revision 190838)
+++ gcc/testsuite/c-c++-common/torture/vector-shift.c	(working copy)
@@ -1,29 +1,30 @@ 
+/* { dg-do run } */
 
 #define vector __attribute__((vector_size(sizeof(int)*4) ))
 
 static vector int allones = {1, 1, 1, 1};
 static vector int allzeros = {0, 0, 0, 0};
 static vector int numbers = {0, 1, 2, 3};
 static vector int numbersleftshiftallones = {0, 2, 4, 6};
 static vector int numbersrightshiftallones = {0, 0, 1, 1};
 
 
 static vector unsigned int uallones = {1, 1, 1, 1};
 static vector unsigned int uallzeros = {0, 0, 0, 0};
 static vector unsigned int unumbers = {0, 1, 2, 3};
 static vector unsigned int unumbersleftshiftallones = {0, 2, 4, 6};
 static vector unsigned int unumbersrightshiftallones = {0, 0, 1, 1};
 
 #define TEST(result, expected) \
 do { \
-  typeof(result) result1 = result; \
+  __typeof__(result) result1 = result; \
   if(sizeof (result1) != sizeof (expected)) \
     __builtin_abort (); \
   if (__builtin_memcmp (&result1, &expected, sizeof(result1)) != 0) \
     __builtin_abort (); \
 }while (0);
 
 int main(void)
 {
   vector int result;
   TEST ((numbers << allzeros), numbers);
Index: gcc/testsuite/c-c++-common/torture/vector-subscript-3.c
===================================================================
--- gcc/testsuite/c-c++-common/torture/vector-subscript-3.c	(revision 190838)
+++ gcc/testsuite/c-c++-common/torture/vector-subscript-3.c	(working copy)
@@ -1,11 +1,11 @@ 
-/* dg-do run */
+/* { dg-do run } */
 #define vector __attribute__((vector_size(16) ))
 
 /* Check whether register declaration of vector type still 
    allow us to subscript this type.  */
 
 typedef vector short myvec_t;
 
 struct vec_s {
     vector short member;
 };
Index: gcc/testsuite/c-c++-common/torture/vector-compare-1.c
===================================================================
--- gcc/testsuite/c-c++-common/torture/vector-compare-1.c	(revision 190838)
+++ gcc/testsuite/c-c++-common/torture/vector-compare-1.c	(working copy)
@@ -1,10 +1,11 @@ 
+/* { dg-do run } */
 #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) ", \
@@ -31,76 +32,76 @@  do { \
 } 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};
+    i0 = (vector (4, INT)){(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};
+    u0 = (vector (4, INT)){(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};
+    s0 = (vector (8, SHORT)){(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};
+    us0 = (vector (8, SHORT)){(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 };
+    c0 = (vector (16, CHAR)){(CHAR)argc, 1,  2,  10,  6, 87, (CHAR)-5, 2, \
+                             (CHAR)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 };
+    uc0 = (vector (16, CHAR)){(CHAR)argc, 1,  2,  10,  6, 87, (CHAR)-5, 2, \
+                              (CHAR)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;
     __typeof (f0 == f1) ifres;
 
Index: gcc/testsuite/c-c++-common/torture/vector-compare-2.c
===================================================================
--- gcc/testsuite/c-c++-common/torture/vector-compare-2.c	(revision 190838)
+++ gcc/testsuite/c-c++-common/torture/vector-compare-2.c	(working copy)
@@ -1,10 +1,12 @@ 
+/* { dg-do run } */
+/* { dg-options "-Wno-psabi" } */
 #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);
Index: gcc/testsuite/c-c++-common/torture/vector-shift2.c
===================================================================
--- gcc/testsuite/c-c++-common/torture/vector-shift2.c	(revision 190838)
+++ gcc/testsuite/c-c++-common/torture/vector-shift2.c	(working copy)
@@ -1,10 +1,11 @@ 
+/* { dg-do run } */
 #define vector(elcount, type)  \
 __attribute__((vector_size((elcount)*sizeof(type)))) type
 
 #define vidx(type, vec, idx) (*((type *) &(vec) + idx))
 #define uint unsigned int
 
 int main (int argc, char *argv[]) {
     vector(4, uint) vuint  = { 1,  2,  3,  4};
     vector(4,  int) vint0  = { 1,  1,  1,  1};
     vector(4,  int) vint1  = {-1, -1, -1, -1};
Index: gcc/testsuite/c-c++-common/vector-shift1.c
===================================================================
--- gcc/testsuite/c-c++-common/vector-shift1.c	(revision 190834)
+++ gcc/testsuite/c-c++-common/vector-shift1.c	(working copy)
@@ -1,18 +1,19 @@ 
 /* { dg-do compile } */
+/* { dg-prune-output "in evaluation of" } */
 #define vector(elcount, type)  \
 __attribute__((vector_size((elcount)*sizeof(type)))) type
 
 int main (int argc, char *argv[]) {
     vector(4, float) vfloat0 = {1., 2., 3., 4.};
     vector(4, float) vfloat1 = {1., 2., 3., 4.};
     
     vector(4,   int) vint   = {1,  1,  1,  1 };
     
     vint <<= vfloat0;  /* { dg-error "nvalid operands to binary <<" } */
     vfloat0 >>= vint;  /* { dg-error "nvalid operands to binary >>" } */
 
-    vfloat0 <<= vfloat1;  /* { dg-error "nvalid operands to binary <<" } */
+    vfloat0 <<= vfloat1;  /* { dg-error "nvalid operands" } */
 
     return 0;
 }
 
Index: gcc/testsuite/c-c++-common/vector-shift3.c
===================================================================
--- gcc/testsuite/c-c++-common/vector-shift3.c	(revision 190834)
+++ gcc/testsuite/c-c++-common/vector-shift3.c	(working copy)
@@ -1,16 +1,16 @@ 
 /* { dg-do compile } */
 
 #define vector(elcount, type)  \
 __attribute__((vector_size((elcount)*sizeof(type)))) type
 
 
 int main (int argc, char *argv[]) {
-    vector(8, short) v0 = {argc,2,3,4,5,6,7};
+    vector(8, short) v0 = {(short)argc,2,3,4,5,6,7};
     short sc;
 
     
-    scalar1 <<= v0; /* { dg-error ".*scalar1.*undeclared" } */
+    scalar1 <<= v0; /* { dg-error "scalar1.*(undeclared|was not declared)" } */
    
     return 0;
 }
 
Index: gcc/testsuite/c-c++-common/vector-compare-1.c
===================================================================
--- gcc/testsuite/c-c++-common/vector-compare-1.c	(revision 190834)
+++ gcc/testsuite/c-c++-common/vector-compare-1.c	(working copy)
@@ -7,13 +7,13 @@  __attribute__((vector_size((elcount)*siz
 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 = (x != p4);   /* { dg-error "incompatible types when assigning to type|cannot convert" } */
   r8 == r4;	    /* { dg-error "comparing vectors with different number of elements" } */
 }
Index: gcc/fold-const.c
===================================================================
--- gcc/fold-const.c	(revision 191291)
+++ gcc/fold-const.c	(working copy)
@@ -7764,21 +7764,21 @@  fold_unary_loc (location_t loc, enum tre
 	  /* If we have (type) (a CMP b) and type is an integral type, return
 	     new expression involving the new type.  Canonicalize
 	     (type) (a CMP b) to (a CMP b) ? (type) true : (type) false for
 	     non-integral type.
 	     Do not fold the result as that would not simplify further, also
 	     folding again results in recursions.  */
 	  if (TREE_CODE (type) == BOOLEAN_TYPE)
 	    return build2_loc (loc, TREE_CODE (op0), type,
 			       TREE_OPERAND (op0, 0),
 			       TREE_OPERAND (op0, 1));
-	  else if (!INTEGRAL_TYPE_P (type))
+	  else if (!INTEGRAL_TYPE_P (type) && TREE_CODE (type) != VECTOR_TYPE)
 	    return build3_loc (loc, COND_EXPR, type, op0,
 			       constant_boolean_node (true, type),
 			       constant_boolean_node (false, type));
 	}
 
       /* Handle cases of two conversions in a row.  */
       if (CONVERT_EXPR_P (op0))
 	{
 	  tree inside_type = TREE_TYPE (TREE_OPERAND (op0, 0));
 	  tree inter_type = TREE_TYPE (op0);
@@ -9822,20 +9822,21 @@  fold_binary_loc (location_t loc,
 
      Before we do that, see if this is a BIT_AND_EXPR or a BIT_IOR_EXPR,
      one of the operands is a comparison and the other is a comparison, a
      BIT_AND_EXPR with the constant 1, or a truth value.  In that case, the
      code below would make the expression more complex.  Change it to a
      TRUTH_{AND,OR}_EXPR.  Likewise, convert a similar NE_EXPR to
      TRUTH_XOR_EXPR and an EQ_EXPR to the inversion of a TRUTH_XOR_EXPR.  */
 
   if ((code == BIT_AND_EXPR || code == BIT_IOR_EXPR
        || code == EQ_EXPR || code == NE_EXPR)
+      && TREE_CODE (type) != VECTOR_TYPE
       && ((truth_value_p (TREE_CODE (arg0))
 	   && (truth_value_p (TREE_CODE (arg1))
 	       || (TREE_CODE (arg1) == BIT_AND_EXPR
 		   && integer_onep (TREE_OPERAND (arg1, 1)))))
 	  || (truth_value_p (TREE_CODE (arg1))
 	      && (truth_value_p (TREE_CODE (arg0))
 		  || (TREE_CODE (arg0) == BIT_AND_EXPR
 		      && integer_onep (TREE_OPERAND (arg0, 1)))))))
     {
       tem = fold_build2_loc (loc, code == BIT_AND_EXPR ? TRUTH_AND_EXPR
Index: gcc/gimple-fold.c
===================================================================
--- gcc/gimple-fold.c	(revision 191291)
+++ gcc/gimple-fold.c	(working copy)
@@ -23,20 +23,21 @@  along with GCC; see the file COPYING3.
 #include "coretypes.h"
 #include "tm.h"
 #include "tree.h"
 #include "flags.h"
 #include "function.h"
 #include "dumpfile.h"
 #include "tree-flow.h"
 #include "tree-ssa-propagate.h"
 #include "target.h"
 #include "gimple-fold.h"
+#include "langhooks.h"
 
 /* Return true when DECL can be referenced from current unit.
    FROM_DECL (if non-null) specify constructor of variable DECL was taken from.
    We can get declarations that are not possible to reference for various
    reasons:
 
      1) When analyzing C++ virtual tables.
 	C++ virtual tables do have known constructors even
 	when they are keyed to other compilation unit.
 	Those tables can contain pointers to methods and vars
@@ -1685,41 +1686,51 @@  and_var_with_comparison_1 (gimple stmt,
    (OP1A CODE1 OP1B) and (OP2A CODE2 OP2B), respectively.
    If this can be done without constructing an intermediate value,
    return the resulting tree; otherwise NULL_TREE is returned.
    This function is deliberately asymmetric as it recurses on SSA_DEFs
    in the first comparison but not the second.  */
 
 static tree
 and_comparisons_1 (enum tree_code code1, tree op1a, tree op1b,
 		   enum tree_code code2, tree op2a, tree op2b)
 {
+  tree truth_type = boolean_type_node;
+  if (TREE_CODE (TREE_TYPE (op1a)) == VECTOR_TYPE)
+    {
+      tree vec_type = TREE_TYPE (op1a);
+      tree elem = lang_hooks.types.type_for_size
+	(GET_MODE_BITSIZE (TYPE_MODE (TREE_TYPE (vec_type))), 0);
+      truth_type = build_opaque_vector_type (elem,
+					     TYPE_VECTOR_SUBPARTS (vec_type));
+    }
+
   /* First check for ((x CODE1 y) AND (x CODE2 y)).  */
   if (operand_equal_p (op1a, op2a, 0)
       && operand_equal_p (op1b, op2b, 0))
     {
       /* Result will be either NULL_TREE, or a combined comparison.  */
       tree t = combine_comparisons (UNKNOWN_LOCATION,
 				    TRUTH_ANDIF_EXPR, code1, code2,
-				    boolean_type_node, op1a, op1b);
+				    truth_type, op1a, op1b);
       if (t)
 	return t;
     }
 
   /* Likewise the swapped case of the above.  */
   if (operand_equal_p (op1a, op2b, 0)
       && operand_equal_p (op1b, op2a, 0))
     {
       /* Result will be either NULL_TREE, or a combined comparison.  */
       tree t = combine_comparisons (UNKNOWN_LOCATION,
 				    TRUTH_ANDIF_EXPR, code1,
 				    swap_tree_comparison (code2),
-				    boolean_type_node, op1a, op1b);
+				    truth_type, op1a, op1b);
       if (t)
 	return t;
     }
 
   /* If both comparisons are of the same value against constants, we might
      be able to merge them.  */
   if (operand_equal_p (op1a, op2a, 0)
       && TREE_CODE (op1b) == INTEGER_CST
       && TREE_CODE (op2b) == INTEGER_CST)
     {
@@ -2147,41 +2158,51 @@  or_var_with_comparison_1 (gimple stmt,
    (OP1A CODE1 OP1B) and (OP2A CODE2 OP2B), respectively.
    If this can be done without constructing an intermediate value,
    return the resulting tree; otherwise NULL_TREE is returned.
    This function is deliberately asymmetric as it recurses on SSA_DEFs
    in the first comparison but not the second.  */
 
 static tree
 or_comparisons_1 (enum tree_code code1, tree op1a, tree op1b,
 		  enum tree_code code2, tree op2a, tree op2b)
 {
+  tree truth_type = boolean_type_node;
+  if (TREE_CODE (TREE_TYPE (op1a)) == VECTOR_TYPE)
+    {
+      tree vec_type = TREE_TYPE (op1a);
+      tree elem = lang_hooks.types.type_for_size
+	(GET_MODE_BITSIZE (TYPE_MODE (TREE_TYPE (vec_type))), 0);
+      truth_type = build_vector_type (elem,
+				      TYPE_VECTOR_SUBPARTS (vec_type));
+    }
+
   /* First check for ((x CODE1 y) OR (x CODE2 y)).  */
   if (operand_equal_p (op1a, op2a, 0)
       && operand_equal_p (op1b, op2b, 0))
     {
       /* Result will be either NULL_TREE, or a combined comparison.  */
       tree t = combine_comparisons (UNKNOWN_LOCATION,
 				    TRUTH_ORIF_EXPR, code1, code2,
-				    boolean_type_node, op1a, op1b);
+				    truth_type, op1a, op1b);
       if (t)
 	return t;
     }
 
   /* Likewise the swapped case of the above.  */
   if (operand_equal_p (op1a, op2b, 0)
       && operand_equal_p (op1b, op2a, 0))
     {
       /* Result will be either NULL_TREE, or a combined comparison.  */
       tree t = combine_comparisons (UNKNOWN_LOCATION,
 				    TRUTH_ORIF_EXPR, code1,
 				    swap_tree_comparison (code2),
-				    boolean_type_node, op1a, op1b);
+				    truth_type, op1a, op1b);
       if (t)
 	return t;
     }
 
   /* If both comparisons are of the same value against constants, we might
      be able to merge them.  */
   if (operand_equal_p (op1a, op2a, 0)
       && TREE_CODE (op1b) == INTEGER_CST
       && TREE_CODE (op2b) == INTEGER_CST)
     {
Index: gcc/cp/typeck.c
===================================================================
--- gcc/cp/typeck.c	(revision 191291)
+++ gcc/cp/typeck.c	(working copy)
@@ -3978,21 +3978,29 @@  cp_build_binary_op (location_t location,
     case TRUTH_AND_EXPR:
     case TRUTH_OR_EXPR:
       result_type = boolean_type_node;
       break;
 
       /* Shift operations: result has same type as first operand;
 	 always convert second operand to int.
 	 Also set SHORT_SHIFT if shifting rightward.  */
 
     case RSHIFT_EXPR:
-      if (code0 == INTEGER_TYPE && code1 == INTEGER_TYPE)
+      if (code0 == VECTOR_TYPE && code1 == VECTOR_TYPE
+	  && TREE_CODE (TREE_TYPE (type0)) == INTEGER_TYPE
+	  && TREE_CODE (TREE_TYPE (type1)) == INTEGER_TYPE
+	  && TYPE_VECTOR_SUBPARTS (type0) == TYPE_VECTOR_SUBPARTS (type1))
+	{
+	  result_type = type0;
+	  converted = 1;
+	}
+      else if (code0 == INTEGER_TYPE && code1 == INTEGER_TYPE)
 	{
 	  result_type = type0;
 	  if (TREE_CODE (op1) == INTEGER_CST)
 	    {
 	      if (tree_int_cst_lt (op1, integer_zero_node))
 		{
 		  if ((complain & tf_warning)
 		      && c_inhibit_evaluation_warnings == 0)
 		    warning (0, "right shift count is negative");
 		}
@@ -4007,21 +4015,29 @@  cp_build_binary_op (location_t location,
 	  /* Convert the shift-count to an integer, regardless of
 	     size of value being shifted.  */
 	  if (TYPE_MAIN_VARIANT (TREE_TYPE (op1)) != integer_type_node)
 	    op1 = cp_convert (integer_type_node, op1, complain);
 	  /* Avoid converting op1 to result_type later.  */
 	  converted = 1;
 	}
       break;
 
     case LSHIFT_EXPR:
-      if (code0 == INTEGER_TYPE && code1 == INTEGER_TYPE)
+      if (code0 == VECTOR_TYPE && code1 == VECTOR_TYPE
+	  && TREE_CODE (TREE_TYPE (type0)) == INTEGER_TYPE
+	  && TREE_CODE (TREE_TYPE (type1)) == INTEGER_TYPE
+	  && TYPE_VECTOR_SUBPARTS (type0) == TYPE_VECTOR_SUBPARTS (type1))
+	{
+	  result_type = type0;
+	  converted = 1;
+	}
+      else if (code0 == INTEGER_TYPE && code1 == INTEGER_TYPE)
 	{
 	  result_type = type0;
 	  if (TREE_CODE (op1) == INTEGER_CST)
 	    {
 	      if (tree_int_cst_lt (op1, integer_zero_node))
 		{
 		  if ((complain & tf_warning)
 		      && c_inhibit_evaluation_warnings == 0)
 		    warning (0, "left shift count is negative");
 		}
@@ -4065,20 +4081,22 @@  cp_build_binary_op (location_t location,
 	    }
 	  /* Convert the shift-count to an integer, regardless of
 	     size of value being shifted.  */
 	  if (TYPE_MAIN_VARIANT (TREE_TYPE (op1)) != integer_type_node)
 	    op1 = cp_convert (integer_type_node, op1, complain);
 	}
       break;
 
     case EQ_EXPR:
     case NE_EXPR:
+      if (code0 == VECTOR_TYPE && code1 == VECTOR_TYPE)
+	goto vector_compare;
       if ((complain & tf_warning)
 	  && (FLOAT_TYPE_P (type0) || FLOAT_TYPE_P (type1)))
 	warning (OPT_Wfloat_equal,
 		 "comparing floating point with == or != is unsafe");
       if ((complain & tf_warning)
 	  && ((TREE_CODE (orig_op0) == STRING_CST && !integer_zerop (op1))
 	      || (TREE_CODE (orig_op1) == STRING_CST && !integer_zerop (op0))))
 	warning (OPT_Waddress, "comparison with string literal results in unspecified behaviour");
 
       build_type = boolean_type_node;
@@ -4307,20 +4325,47 @@  cp_build_binary_op (location_t location,
     case GE_EXPR:
     case LT_EXPR:
     case GT_EXPR:
       if (TREE_CODE (orig_op0) == STRING_CST
 	  || TREE_CODE (orig_op1) == STRING_CST)
 	{
 	  if (complain & tf_warning)
 	    warning (OPT_Waddress, "comparison with string literal results in unspecified behaviour");
 	}
 
+      if (code0 == VECTOR_TYPE && code1 == VECTOR_TYPE)
+	{
+	vector_compare:
+	  tree intt;
+	  if (!same_type_ignoring_top_level_qualifiers_p (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 (GET_MODE_BITSIZE
+					   (TYPE_MODE (TREE_TYPE (type0))), 0);
+	  result_type = build_vector_type (intt,
+					   TYPE_VECTOR_SUBPARTS (type0));
+	  converted = 1;
+	  break;
+	}
       build_type = boolean_type_node;
       if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE
 	   || code0 == ENUMERAL_TYPE)
 	   && (code1 == INTEGER_TYPE || code1 == REAL_TYPE
 	       || code1 == ENUMERAL_TYPE))
 	short_compare = 1;
       else if (code0 == POINTER_TYPE && code1 == POINTER_TYPE)
 	result_type = composite_pointer_type (type0, type1, op0, op1,
 					      CPO_COMPARISON, complain);
       else if (code0 == POINTER_TYPE && null_ptr_cst_p (op1))