diff mbox

Fold VEC_COND_EXPR to abs, min, max

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

Commit Message

Marc Glisse March 17, 2013, 3:46 p.m. UTC
Hello,

this patch adds a bit of folding to VEC_COND_EXPR so it is possible to 
generate ABS_EXPR and MAX_EXPR for vectors without relying on the 
vectorizer. I would have preferred to merge the COND_EXPR and 
VEC_COND_EXPR cases, but there are too many things that need fixing first, 
so I just copied the most relevant block. Folding from the front-end is 
ugly, but that's how the scalar case works, and they can both move to 
gimple folding together later.

Bootstrap + testsuite on x86_64-linux-gnu.

2013-03-17  Marc Glisse  <marc.glisse@inria.fr>

gcc/
 	* fold-const.c (fold_cond_expr_with_comparison): Use build_zero_cst.
 	VEC_COND_EXPR cannot be lvalues.
 	(fold_ternary_loc) <VEC_COND_EXPR>: Call fold_cond_expr_with_comparison.

gcc/cp/
 	* call.c (build_conditional_expr_1): Fold VEC_COND_EXPR.

gcc/testsuite/
 	* g++.dg/ext/vector21.C: New testcase.

Comments

Richard Biener March 18, 2013, 9:30 a.m. UTC | #1
On Sun, Mar 17, 2013 at 4:46 PM, Marc Glisse <marc.glisse@inria.fr> wrote:
> Hello,
>
> this patch adds a bit of folding to VEC_COND_EXPR so it is possible to
> generate ABS_EXPR and MAX_EXPR for vectors without relying on the
> vectorizer. I would have preferred to merge the COND_EXPR and VEC_COND_EXPR
> cases, but there are too many things that need fixing first, so I just
> copied the most relevant block. Folding from the front-end is ugly, but
> that's how the scalar case works, and they can both move to gimple folding
> together later.
>
> Bootstrap + testsuite on x86_64-linux-gnu.
>
> 2013-03-17  Marc Glisse  <marc.glisse@inria.fr>
>
> gcc/
>         * fold-const.c (fold_cond_expr_with_comparison): Use build_zero_cst.
>         VEC_COND_EXPR cannot be lvalues.
>         (fold_ternary_loc) <VEC_COND_EXPR>: Call
> fold_cond_expr_with_comparison.
>
> gcc/cp/
>         * call.c (build_conditional_expr_1): Fold VEC_COND_EXPR.
>
> gcc/testsuite/
>         * g++.dg/ext/vector21.C: New testcase.
>
> --
> Marc Glisse
> Index: gcc/testsuite/g++.dg/ext/vector21.C
> ===================================================================
> --- gcc/testsuite/g++.dg/ext/vector21.C (revision 0)
> +++ gcc/testsuite/g++.dg/ext/vector21.C (revision 0)
> @@ -0,0 +1,39 @@
> +/* { dg-do compile } */
> +/* { dg-options "-O -fdump-tree-gimple" } */
> +
> +typedef int vec __attribute__ ((vector_size (4 * sizeof (int))));
> +
> +void f1 (vec *x)
> +{
> +  *x = (*x >= 0) ? *x : -*x;
> +}
> +void f2 (vec *x)
> +{
> +  *x = (0 < *x) ? *x : -*x;
> +}
> +void g1 (vec *x)
> +{
> +  *x = (*x < 0) ? -*x : *x;
> +}
> +void g2 (vec *x)
> +{
> +  *x = (0 > *x) ? -*x : *x;
> +}
> +void h (vec *x, vec *y)
> +{
> +  *x = (*x < *y) ? *y : *x;
> +}
> +void i (vec *x, vec *y)
> +{
> +  *x = (*x < *y) ? *x : *y;
> +}
> +void j (vec *x, vec *y)
> +{
> +  *x = (*x < *y) ? *x : *x;
> +}
> +
> +/* { dg-final { scan-tree-dump-times "ABS_EXPR" 4 "gimple" } } */
> +/* { dg-final { scan-tree-dump "MIN_EXPR" "gimple" } } */
> +/* { dg-final { scan-tree-dump "MAX_EXPR" "gimple" } } */
> +/* { dg-final { scan-tree-dump-not "VEC_COND_EXPR" "gimple" } } */
> +/* { dg-final { cleanup-tree-dump "gimple" } } */
>
> Property changes on: gcc/testsuite/g++.dg/ext/vector21.C
> ___________________________________________________________________
> Added: svn:keywords
>    + Author Date Id Revision URL
> Added: svn:eol-style
>    + native
>
> Index: gcc/fold-const.c
> ===================================================================
> --- gcc/fold-const.c    (revision 196748)
> +++ gcc/fold-const.c    (working copy)
> @@ -4625,21 +4625,21 @@ fold_cond_expr_with_comparison (location
>       A == 0 ? A : 0 is always 0 unless A is -0.  Note that
>       both transformations are correct when A is NaN: A != 0
>       is then true, and A == 0 is false.  */
>
>    if (!HONOR_SIGNED_ZEROS (TYPE_MODE (type))
>        && integer_zerop (arg01) && integer_zerop (arg2))
>      {
>        if (comp_code == NE_EXPR)
>         return pedantic_non_lvalue_loc (loc, fold_convert_loc (loc, type,
> arg1));
>        else if (comp_code == EQ_EXPR)
> -       return build_int_cst (type, 0);
> +       return build_zero_cst (type);
>      }
>
>    /* Try some transformations of A op B ? A : B.
>
>       A == B? A : B    same as B
>       A != B? A : B    same as A
>       A >= B? A : B    same as max (A, B)
>       A > B?  A : B    same as max (B, A)
>       A <= B? A : B    same as min (A, B)
>       A < B?  A : B    same as min (B, A)
> @@ -4662,21 +4662,22 @@ fold_cond_expr_with_comparison (location
>       expressions will be false, so all four give B.  The min()
>       and max() versions would give a NaN instead.  */
>    if (!HONOR_SIGNED_ZEROS (TYPE_MODE (type))
>        && operand_equal_for_comparison_p (arg01, arg2, arg00)
>        /* Avoid these transformations if the COND_EXPR may be used
>          as an lvalue in the C++ front-end.  PR c++/19199.  */
>        && (in_gimple_form
>           || (strcmp (lang_hooks.name, "GNU C++") != 0
>               && strcmp (lang_hooks.name, "GNU Objective-C++") != 0)
>           || ! maybe_lvalue_p (arg1)
> -         || ! maybe_lvalue_p (arg2)))
> +         || ! maybe_lvalue_p (arg2)
> +         || TREE_CODE (TREE_TYPE (arg1)) == VECTOR_TYPE))

You mean that the VEC_COND_EXPRs can never be used as an lvalue in
the C++ frontend?

>      {
>        tree comp_op0 = arg00;
>        tree comp_op1 = arg01;
>        tree comp_type = TREE_TYPE (comp_op0);
>
>        /* Avoid adding NOP_EXPRs in case this is an lvalue.  */
>        if (TYPE_MAIN_VARIANT (comp_type) == TYPE_MAIN_VARIANT (type))
>         {
>           comp_type = type;
>           comp_op0 = arg1;
> @@ -14138,20 +14139,51 @@ fold_ternary_loc (location_t loc, enum t
>        return NULL_TREE;
>
>      case VEC_COND_EXPR:
>        if (TREE_CODE (arg0) == VECTOR_CST)
>         {
>           if (integer_all_onesp (arg0) && !TREE_SIDE_EFFECTS (op2))
>             return pedantic_non_lvalue_loc (loc, op1);
>           if (integer_zerop (arg0) && !TREE_SIDE_EFFECTS (op1))
>             return pedantic_non_lvalue_loc (loc, op2);
>         }
> +      if (operand_equal_p (arg1, op2, 0))
> +       return pedantic_omit_one_operand_loc (loc, type, arg1, arg0);
> +
> +      /* If we have A op B ? A : C, we may be able to convert this to a
> +        simpler expression, depending on the operation and the values
> +        of B and C.  Signed zeros prevent all of these transformations,
> +        for reasons given above each one.
> +
> +         Also try swapping the arguments and inverting the conditional.  */
> +      if (COMPARISON_CLASS_P (arg0)
> +         && operand_equal_p (TREE_OPERAND (arg0, 0), arg1, 0)
> +         && !HONOR_SIGNED_ZEROS (TYPE_MODE (TREE_TYPE (arg1))))
> +       {
> +         tem = fold_cond_expr_with_comparison (loc, type, arg0, op1, op2);
> +         if (tem)
> +           return tem;
> +       }
> +
> +      if (COMPARISON_CLASS_P (arg0)
> +         && operand_equal_p (TREE_OPERAND (arg0, 0), op2, 0)
> +         && !HONOR_SIGNED_ZEROS (TYPE_MODE (TREE_TYPE (op2))))
> +       {
> +         location_t loc0 = expr_location_or (arg0, loc);
> +         tem = fold_truth_not_expr (loc0, arg0);
> +         if (tem && COMPARISON_CLASS_P (tem))
> +           {
> +             tem = fold_cond_expr_with_comparison (loc, type, tem, op2,
> op1);
> +             if (tem)
> +               return tem;
> +           }
> +       }
>        return NULL_TREE;

Btw, instead of copying this whole block I'd prefer

     case COND_EXPR:
     case VEC_COND_EXPR:
         ... common cases...

         /* ???  Fixup the code below for VEC_COND_EXRP.  */
         if (code == VEC_COND_EXPR)
           break;

Thanks,
Richard.

>      case CALL_EXPR:
>        /* CALL_EXPRs used to be ternary exprs.  Catch any mistaken uses
>          of fold_ternary on them.  */
>        gcc_unreachable ();
>
>      case BIT_FIELD_REF:
>        if ((TREE_CODE (arg0) == VECTOR_CST
>            || (TREE_CODE (arg0) == CONSTRUCTOR
> Index: gcc/cp/call.c
> ===================================================================
> --- gcc/cp/call.c       (revision 196748)
> +++ gcc/cp/call.c       (working copy)
> @@ -4430,23 +4430,23 @@ build_conditional_expr_1 (tree arg1, tre
>           || TYPE_SIZE (arg1_type) != TYPE_SIZE (arg2_type))
>         {
>           if (complain & tf_error)
>             error ("incompatible vector types in conditional expression: "
>                    "%qT, %qT and %qT", TREE_TYPE (arg1), TREE_TYPE
> (orig_arg2),
>                    TREE_TYPE (orig_arg3));
>           return error_mark_node;
>         }
>
>        if (!COMPARISON_CLASS_P (arg1))
> -       arg1 = build2 (NE_EXPR, signed_type_for (arg1_type), arg1,
> +       arg1 = fold_build2 (NE_EXPR, signed_type_for (arg1_type), arg1,
>                        build_zero_cst (arg1_type));
> -      return build3 (VEC_COND_EXPR, arg2_type, arg1, arg2, arg3);
> +      return fold_build3 (VEC_COND_EXPR, arg2_type, arg1, arg2, arg3);
>      }
>
>    /* [expr.cond]
>
>       The first expression is implicitly converted to bool (clause
>       _conv_).  */
>    arg1 = perform_implicit_conversion_flags (boolean_type_node, arg1,
> complain,
>                                             LOOKUP_NORMAL);
>    if (error_operand_p (arg1))
>      return error_mark_node;
>
Marc Glisse March 18, 2013, 10:27 a.m. UTC | #2
On Mon, 18 Mar 2013, Richard Biener wrote:

>> 2013-03-17  Marc Glisse  <marc.glisse@inria.fr>
>>
>> gcc/
>>         * fold-const.c (fold_cond_expr_with_comparison): Use build_zero_cst.
>>         VEC_COND_EXPR cannot be lvalues.
>>         (fold_ternary_loc) <VEC_COND_EXPR>: Call
>> fold_cond_expr_with_comparison.
>>
>> gcc/cp/
>>         * call.c (build_conditional_expr_1): Fold VEC_COND_EXPR.
>>
>> gcc/testsuite/
>>         * g++.dg/ext/vector21.C: New testcase.

>> @@ -4662,21 +4662,22 @@ fold_cond_expr_with_comparison (location
>>       expressions will be false, so all four give B.  The min()
>>       and max() versions would give a NaN instead.  */
>>    if (!HONOR_SIGNED_ZEROS (TYPE_MODE (type))
>>        && operand_equal_for_comparison_p (arg01, arg2, arg00)
>>        /* Avoid these transformations if the COND_EXPR may be used
>>          as an lvalue in the C++ front-end.  PR c++/19199.  */
>>        && (in_gimple_form
>>           || (strcmp (lang_hooks.name, "GNU C++") != 0
>>               && strcmp (lang_hooks.name, "GNU Objective-C++") != 0)
>>           || ! maybe_lvalue_p (arg1)
>> -         || ! maybe_lvalue_p (arg2)))
>> +         || ! maybe_lvalue_p (arg2)
>> +         || TREE_CODE (TREE_TYPE (arg1)) == VECTOR_TYPE))
>
> You mean that the VEC_COND_EXPRs can never be used as an lvalue in
> the C++ frontend?

Yes, as I mention in the ChangeLog. Not just the C++ front-end, it never 
makes sense to use a VEC_COND_EXPR as an lvalue, it really is just a 
ternary variant of BIT_AND_EXPR.

> Btw, instead of copying this whole block I'd prefer
>
>     case COND_EXPR:
>     case VEC_COND_EXPR:
>         ... common cases...
>
>         /* ???  Fixup the code below for VEC_COND_EXRP.  */
>         if (code == VEC_COND_EXPR)
>           break;

Makes sense, I'll rework the patch.

Thanks,
Richard Biener March 18, 2013, 10:45 a.m. UTC | #3
On Mon, Mar 18, 2013 at 11:27 AM, Marc Glisse <marc.glisse@inria.fr> wrote:
> On Mon, 18 Mar 2013, Richard Biener wrote:
>
>>> 2013-03-17  Marc Glisse  <marc.glisse@inria.fr>
>>>
>>> gcc/
>>>         * fold-const.c (fold_cond_expr_with_comparison): Use
>>> build_zero_cst.
>>>         VEC_COND_EXPR cannot be lvalues.
>>>         (fold_ternary_loc) <VEC_COND_EXPR>: Call
>>> fold_cond_expr_with_comparison.
>>>
>>> gcc/cp/
>>>         * call.c (build_conditional_expr_1): Fold VEC_COND_EXPR.
>>>
>>> gcc/testsuite/
>>>         * g++.dg/ext/vector21.C: New testcase.
>
>
>>> @@ -4662,21 +4662,22 @@ fold_cond_expr_with_comparison (location
>>>       expressions will be false, so all four give B.  The min()
>>>       and max() versions would give a NaN instead.  */
>>>    if (!HONOR_SIGNED_ZEROS (TYPE_MODE (type))
>>>        && operand_equal_for_comparison_p (arg01, arg2, arg00)
>>>        /* Avoid these transformations if the COND_EXPR may be used
>>>          as an lvalue in the C++ front-end.  PR c++/19199.  */
>>>        && (in_gimple_form
>>>           || (strcmp (lang_hooks.name, "GNU C++") != 0
>>>               && strcmp (lang_hooks.name, "GNU Objective-C++") != 0)
>>>           || ! maybe_lvalue_p (arg1)
>>> -         || ! maybe_lvalue_p (arg2)))
>>> +         || ! maybe_lvalue_p (arg2)
>>> +         || TREE_CODE (TREE_TYPE (arg1)) == VECTOR_TYPE))
>>
>>
>> You mean that the VEC_COND_EXPRs can never be used as an lvalue in
>> the C++ frontend?
>
>
> Yes, as I mention in the ChangeLog. Not just the C++ front-end, it never
> makes sense to use a VEC_COND_EXPR as an lvalue, it really is just a ternary
> variant of BIT_AND_EXPR.

Then please add a && TREE_CODE == COND_EXPR around the
code handling only COND_EXPRs instead.

Richard.

>
>> Btw, instead of copying this whole block I'd prefer
>>
>>     case COND_EXPR:
>>     case VEC_COND_EXPR:
>>         ... common cases...
>>
>>         /* ???  Fixup the code below for VEC_COND_EXRP.  */
>>         if (code == VEC_COND_EXPR)
>>           break;
>
>
> Makes sense, I'll rework the patch.
>
> Thanks,
>
> --
> Marc Glisse
Marc Glisse March 18, 2013, 11:06 a.m. UTC | #4
On Mon, 18 Mar 2013, Richard Biener wrote:

> On Mon, Mar 18, 2013 at 11:27 AM, Marc Glisse <marc.glisse@inria.fr> wrote:
>> On Mon, 18 Mar 2013, Richard Biener wrote:
>>> You mean that the VEC_COND_EXPRs can never be used as an lvalue in
>>> the C++ frontend?
>>
>> Yes, as I mention in the ChangeLog. Not just the C++ front-end, it never
>> makes sense to use a VEC_COND_EXPR as an lvalue, it really is just a ternary
>> variant of BIT_AND_EXPR.
>
> Then please add a && TREE_CODE == COND_EXPR around the
> code handling only COND_EXPRs instead.

Hmm, there isn't one. There is just a block of code that is disabled when 
the compiler is not certain that the result is not an lvalue. And the 
arguments it can use to prove that are:
* we are in gimple form
* we are not doing C++
* one of the alternatives is not an lvalue
* (new) it is a vec_cond_expr

Apart from changing TREE_CODE == VEC_COND_EXPR to TREE_CODE != COND_EXPR, 
I am not sure what to change.

(Looking at the patch, I may have forgotten to check for side effects 
somewhere, the tests needed are not exactly the same as for COND_EXPR 
since VEC_COND_EXPR is not lazy, I'll check that before resubmitting)
Richard Biener March 18, 2013, 11:10 a.m. UTC | #5
On Mon, Mar 18, 2013 at 12:06 PM, Marc Glisse <marc.glisse@inria.fr> wrote:
> On Mon, 18 Mar 2013, Richard Biener wrote:
>
>> On Mon, Mar 18, 2013 at 11:27 AM, Marc Glisse <marc.glisse@inria.fr>
>> wrote:
>>>
>>> On Mon, 18 Mar 2013, Richard Biener wrote:
>>>>
>>>> You mean that the VEC_COND_EXPRs can never be used as an lvalue in
>>>> the C++ frontend?
>>>
>>>
>>> Yes, as I mention in the ChangeLog. Not just the C++ front-end, it never
>>> makes sense to use a VEC_COND_EXPR as an lvalue, it really is just a
>>> ternary
>>> variant of BIT_AND_EXPR.
>>
>>
>> Then please add a && TREE_CODE == COND_EXPR around the
>> code handling only COND_EXPRs instead.
>
>
> Hmm, there isn't one. There is just a block of code that is disabled when
> the compiler is not certain that the result is not an lvalue. And the
> arguments it can use to prove that are:
> * we are in gimple form
> * we are not doing C++
> * one of the alternatives is not an lvalue
> * (new) it is a vec_cond_expr
>
> Apart from changing TREE_CODE == VEC_COND_EXPR to TREE_CODE != COND_EXPR, I
> am not sure what to change.
>
> (Looking at the patch, I may have forgotten to check for side effects
> somewhere, the tests needed are not exactly the same as for COND_EXPR since
> VEC_COND_EXPR is not lazy, I'll check that before resubmitting)

Hmm, I see we don't even have the code available in
fold_cond_expr_with_comparison.
So use instead

  if (!HONOR_SIGNED_ZEROS (TYPE_MODE (type))
      && operand_equal_for_comparison_p (arg01, arg2, arg00)
      /* Avoid these transformations if the COND_EXPR may be used
         as an lvalue in the C++ front-end.  PR c++/19199.  */
      && (in_gimple_form
          || VECTOR_TYPE_P (type)
          || (strcmp (lang_hooks.name, "GNU C++") != 0
              && strcmp (lang_hooks.name, "GNU Objective-C++") != 0)
          || ! maybe_lvalue_p (arg1)
          || ! maybe_lvalue_p (arg2)))

err - there isn't a VECTOR_TYPE_P predicate - time to add one ;)

Thanks,
Richard.

> --
> Marc Glisse
diff mbox

Patch

Index: gcc/testsuite/g++.dg/ext/vector21.C
===================================================================
--- gcc/testsuite/g++.dg/ext/vector21.C	(revision 0)
+++ gcc/testsuite/g++.dg/ext/vector21.C	(revision 0)
@@ -0,0 +1,39 @@ 
+/* { dg-do compile } */
+/* { dg-options "-O -fdump-tree-gimple" } */
+
+typedef int vec __attribute__ ((vector_size (4 * sizeof (int))));
+
+void f1 (vec *x)
+{
+  *x = (*x >= 0) ? *x : -*x;
+}
+void f2 (vec *x)
+{
+  *x = (0 < *x) ? *x : -*x;
+}
+void g1 (vec *x)
+{
+  *x = (*x < 0) ? -*x : *x;
+}
+void g2 (vec *x)
+{
+  *x = (0 > *x) ? -*x : *x;
+}
+void h (vec *x, vec *y)
+{
+  *x = (*x < *y) ? *y : *x;
+}
+void i (vec *x, vec *y)
+{
+  *x = (*x < *y) ? *x : *y;
+}
+void j (vec *x, vec *y)
+{
+  *x = (*x < *y) ? *x : *x;
+}
+
+/* { dg-final { scan-tree-dump-times "ABS_EXPR" 4 "gimple" } } */
+/* { dg-final { scan-tree-dump "MIN_EXPR" "gimple" } } */
+/* { dg-final { scan-tree-dump "MAX_EXPR" "gimple" } } */
+/* { dg-final { scan-tree-dump-not "VEC_COND_EXPR" "gimple" } } */
+/* { dg-final { cleanup-tree-dump "gimple" } } */

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

Index: gcc/fold-const.c
===================================================================
--- gcc/fold-const.c	(revision 196748)
+++ gcc/fold-const.c	(working copy)
@@ -4625,21 +4625,21 @@  fold_cond_expr_with_comparison (location
      A == 0 ? A : 0 is always 0 unless A is -0.  Note that
      both transformations are correct when A is NaN: A != 0
      is then true, and A == 0 is false.  */
 
   if (!HONOR_SIGNED_ZEROS (TYPE_MODE (type))
       && integer_zerop (arg01) && integer_zerop (arg2))
     {
       if (comp_code == NE_EXPR)
 	return pedantic_non_lvalue_loc (loc, fold_convert_loc (loc, type, arg1));
       else if (comp_code == EQ_EXPR)
-	return build_int_cst (type, 0);
+	return build_zero_cst (type);
     }
 
   /* Try some transformations of A op B ? A : B.
 
      A == B? A : B    same as B
      A != B? A : B    same as A
      A >= B? A : B    same as max (A, B)
      A > B?  A : B    same as max (B, A)
      A <= B? A : B    same as min (A, B)
      A < B?  A : B    same as min (B, A)
@@ -4662,21 +4662,22 @@  fold_cond_expr_with_comparison (location
      expressions will be false, so all four give B.  The min()
      and max() versions would give a NaN instead.  */
   if (!HONOR_SIGNED_ZEROS (TYPE_MODE (type))
       && operand_equal_for_comparison_p (arg01, arg2, arg00)
       /* Avoid these transformations if the COND_EXPR may be used
 	 as an lvalue in the C++ front-end.  PR c++/19199.  */
       && (in_gimple_form
 	  || (strcmp (lang_hooks.name, "GNU C++") != 0
 	      && strcmp (lang_hooks.name, "GNU Objective-C++") != 0)
 	  || ! maybe_lvalue_p (arg1)
-	  || ! maybe_lvalue_p (arg2)))
+	  || ! maybe_lvalue_p (arg2)
+	  || TREE_CODE (TREE_TYPE (arg1)) == VECTOR_TYPE))
     {
       tree comp_op0 = arg00;
       tree comp_op1 = arg01;
       tree comp_type = TREE_TYPE (comp_op0);
 
       /* Avoid adding NOP_EXPRs in case this is an lvalue.  */
       if (TYPE_MAIN_VARIANT (comp_type) == TYPE_MAIN_VARIANT (type))
 	{
 	  comp_type = type;
 	  comp_op0 = arg1;
@@ -14138,20 +14139,51 @@  fold_ternary_loc (location_t loc, enum t
       return NULL_TREE;
 
     case VEC_COND_EXPR:
       if (TREE_CODE (arg0) == VECTOR_CST)
 	{
 	  if (integer_all_onesp (arg0) && !TREE_SIDE_EFFECTS (op2))
 	    return pedantic_non_lvalue_loc (loc, op1);
 	  if (integer_zerop (arg0) && !TREE_SIDE_EFFECTS (op1))
 	    return pedantic_non_lvalue_loc (loc, op2);
 	}
+      if (operand_equal_p (arg1, op2, 0))
+	return pedantic_omit_one_operand_loc (loc, type, arg1, arg0);
+
+      /* If we have A op B ? A : C, we may be able to convert this to a
+	 simpler expression, depending on the operation and the values
+	 of B and C.  Signed zeros prevent all of these transformations,
+	 for reasons given above each one.
+
+         Also try swapping the arguments and inverting the conditional.  */
+      if (COMPARISON_CLASS_P (arg0)
+	  && operand_equal_p (TREE_OPERAND (arg0, 0), arg1, 0)
+	  && !HONOR_SIGNED_ZEROS (TYPE_MODE (TREE_TYPE (arg1))))
+	{
+	  tem = fold_cond_expr_with_comparison (loc, type, arg0, op1, op2);
+	  if (tem)
+	    return tem;
+	}
+
+      if (COMPARISON_CLASS_P (arg0)
+	  && operand_equal_p (TREE_OPERAND (arg0, 0), op2, 0)
+	  && !HONOR_SIGNED_ZEROS (TYPE_MODE (TREE_TYPE (op2))))
+	{
+	  location_t loc0 = expr_location_or (arg0, loc);
+	  tem = fold_truth_not_expr (loc0, arg0);
+	  if (tem && COMPARISON_CLASS_P (tem))
+	    {
+	      tem = fold_cond_expr_with_comparison (loc, type, tem, op2, op1);
+	      if (tem)
+		return tem;
+	    }
+	}
       return NULL_TREE;
 
     case CALL_EXPR:
       /* CALL_EXPRs used to be ternary exprs.  Catch any mistaken uses
 	 of fold_ternary on them.  */
       gcc_unreachable ();
 
     case BIT_FIELD_REF:
       if ((TREE_CODE (arg0) == VECTOR_CST
 	   || (TREE_CODE (arg0) == CONSTRUCTOR
Index: gcc/cp/call.c
===================================================================
--- gcc/cp/call.c	(revision 196748)
+++ gcc/cp/call.c	(working copy)
@@ -4430,23 +4430,23 @@  build_conditional_expr_1 (tree arg1, tre
 	  || TYPE_SIZE (arg1_type) != TYPE_SIZE (arg2_type))
 	{
 	  if (complain & tf_error)
 	    error ("incompatible vector types in conditional expression: "
 		   "%qT, %qT and %qT", TREE_TYPE (arg1), TREE_TYPE (orig_arg2),
 		   TREE_TYPE (orig_arg3));
 	  return error_mark_node;
 	}
 
       if (!COMPARISON_CLASS_P (arg1))
-	arg1 = build2 (NE_EXPR, signed_type_for (arg1_type), arg1,
+	arg1 = fold_build2 (NE_EXPR, signed_type_for (arg1_type), arg1,
 		       build_zero_cst (arg1_type));
-      return build3 (VEC_COND_EXPR, arg2_type, arg1, arg2, arg3);
+      return fold_build3 (VEC_COND_EXPR, arg2_type, arg1, arg2, arg3);
     }
 
   /* [expr.cond]
 
      The first expression is implicitly converted to bool (clause
      _conv_).  */
   arg1 = perform_implicit_conversion_flags (boolean_type_node, arg1, complain,
 					    LOOKUP_NORMAL);
   if (error_operand_p (arg1))
     return error_mark_node;