public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* Fold VEC_COND_EXPR to abs, min, max
@ 2013-03-17 15:47 Marc Glisse
  2013-03-18  9:30 ` Richard Biener
       [not found] ` <alpine.DEB.2.02.1303190848180.32548@stedding.saclay.inria.fr>
  0 siblings, 2 replies; 7+ messages in thread
From: Marc Glisse @ 2013-03-17 15:47 UTC (permalink / raw)
  To: gcc-patches

[-- Attachment #1: Type: TEXT/PLAIN, Size: 882 bytes --]

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

[-- Attachment #2: Type: TEXT/PLAIN, Size: 6414 bytes --]

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;

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: Fold VEC_COND_EXPR to abs, min, max
  2013-03-17 15:47 Fold VEC_COND_EXPR to abs, min, max Marc Glisse
@ 2013-03-18  9:30 ` Richard Biener
  2013-03-18 10:27   ` Marc Glisse
       [not found] ` <alpine.DEB.2.02.1303190848180.32548@stedding.saclay.inria.fr>
  1 sibling, 1 reply; 7+ messages in thread
From: Richard Biener @ 2013-03-18  9:30 UTC (permalink / raw)
  To: Marc Glisse; +Cc: gcc-patches

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;
>

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: Fold VEC_COND_EXPR to abs, min, max
  2013-03-18  9:30 ` Richard Biener
@ 2013-03-18 10:27   ` Marc Glisse
  2013-03-18 10:45     ` Richard Biener
  0 siblings, 1 reply; 7+ messages in thread
From: Marc Glisse @ 2013-03-18 10:27 UTC (permalink / raw)
  To: Richard Biener; +Cc: gcc-patches

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,

-- 
Marc Glisse

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: Fold VEC_COND_EXPR to abs, min, max
  2013-03-18 10:27   ` Marc Glisse
@ 2013-03-18 10:45     ` Richard Biener
  2013-03-18 11:06       ` Marc Glisse
  0 siblings, 1 reply; 7+ messages in thread
From: Richard Biener @ 2013-03-18 10:45 UTC (permalink / raw)
  To: Marc Glisse; +Cc: gcc-patches

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

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: Fold VEC_COND_EXPR to abs, min, max
  2013-03-18 10:45     ` Richard Biener
@ 2013-03-18 11:06       ` Marc Glisse
  2013-03-18 11:11         ` Richard Biener
  0 siblings, 1 reply; 7+ messages in thread
From: Marc Glisse @ 2013-03-18 11:06 UTC (permalink / raw)
  To: Richard Biener; +Cc: gcc-patches

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)

-- 
Marc Glisse

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: Fold VEC_COND_EXPR to abs, min, max
  2013-03-18 11:06       ` Marc Glisse
@ 2013-03-18 11:11         ` Richard Biener
  0 siblings, 0 replies; 7+ messages in thread
From: Richard Biener @ 2013-03-18 11:11 UTC (permalink / raw)
  To: Marc Glisse; +Cc: gcc-patches

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

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: Fold VEC_COND_EXPR to abs, min, max
       [not found] ` <alpine.DEB.2.02.1303190848180.32548@stedding.saclay.inria.fr>
@ 2013-03-19 15:15   ` Richard Biener
  0 siblings, 0 replies; 7+ messages in thread
From: Richard Biener @ 2013-03-19 15:15 UTC (permalink / raw)
  To: Marc Glisse; +Cc: gcc-patches

On Tue, Mar 19, 2013 at 9:06 AM, Marc Glisse <marc.glisse@inria.fr> wrote:
> Hello,
>
> new version of the patch. Note that for the simplification from {-1,-1}?a:b
> to a, I removed the test that b has no side effects and call
> pedantic_omit_one_operand_loc instead.
>
>
> Bootstrap + testsuite on x86_64-linux-gnu.

Ok.

Thanks,
Richard.

> 2013-03-19  Marc Glisse  <marc.glisse@inria.fr>
>
> gcc/
>         * tree.h (VECTOR_TYPE_P): New macro.
>         (VECTOR_INTEGER_TYPE_P, VECTOR_FLOAT_TYPE_P, FLOAT_TYPE_P,
>         TYPE_MODE): Use it.
>
>         * fold-const.c (fold_cond_expr_with_comparison): Use build_zero_cst.
>         VEC_COND_EXPR cannot be lvalues.
>         (fold_ternary_loc) <VEC_COND_EXPR>: Merge with the COND_EXPR case.
>
>
> 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:eol-style
>    + native
> Added: svn:keywords
>    + Author Date Id Revision URL
>
> 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;
> Index: gcc/tree.h
> ===================================================================
> --- gcc/tree.h  (revision 196748)
> +++ gcc/tree.h  (working copy)
> @@ -974,20 +974,24 @@ extern void omp_clause_range_check_faile
>          && (TREE_TYPE (EXP)                                    \
>              == TREE_TYPE (TREE_OPERAND (EXP, 0))))             \
>      (EXP) = TREE_OPERAND (EXP, 0)
>
>  /* Remove unnecessary type conversions according to
>     tree_ssa_useless_type_conversion.  */
>
>  #define STRIP_USELESS_TYPE_CONVERSION(EXP) \
>    (EXP) = tree_ssa_strip_useless_type_conversions (EXP)
>
> +/* Nonzero if TYPE represents a vector type.  */
> +
> +#define VECTOR_TYPE_P(TYPE) (TREE_CODE (TYPE) == VECTOR_TYPE)
> +
>  /* Nonzero if TYPE represents an integral type.  Note that we do not
>     include COMPLEX types here.  Keep these checks in ascending code
>     order.  */
>
>  #define INTEGRAL_TYPE_P(TYPE)  \
>    (TREE_CODE (TYPE) == ENUMERAL_TYPE  \
>     || TREE_CODE (TYPE) == BOOLEAN_TYPE \
>     || TREE_CODE (TYPE) == INTEGER_TYPE)
>
>  /* Nonzero if TYPE represents a non-saturating fixed-point type.  */
> @@ -1009,39 +1013,39 @@ extern void omp_clause_range_check_faile
>  #define SCALAR_FLOAT_TYPE_P(TYPE) (TREE_CODE (TYPE) == REAL_TYPE)
>
>  /* Nonzero if TYPE represents a complex floating-point type.  */
>
>  #define COMPLEX_FLOAT_TYPE_P(TYPE)     \
>    (TREE_CODE (TYPE) == COMPLEX_TYPE    \
>     && TREE_CODE (TREE_TYPE (TYPE)) == REAL_TYPE)
>
>  /* Nonzero if TYPE represents a vector integer type.  */
>
> -#define VECTOR_INTEGER_TYPE_P(TYPE)                   \
> -             (TREE_CODE (TYPE) == VECTOR_TYPE      \
> -                 && TREE_CODE (TREE_TYPE (TYPE)) == INTEGER_TYPE)
> +#define VECTOR_INTEGER_TYPE_P(TYPE)                    \
> +  (VECTOR_TYPE_P (TYPE)                                        \
> +   && TREE_CODE (TREE_TYPE (TYPE)) == INTEGER_TYPE)
>
>
>  /* Nonzero if TYPE represents a vector floating-point type.  */
>
>  #define VECTOR_FLOAT_TYPE_P(TYPE)      \
> -  (TREE_CODE (TYPE) == VECTOR_TYPE     \
> +  (VECTOR_TYPE_P (TYPE)                        \
>     && TREE_CODE (TREE_TYPE (TYPE)) == REAL_TYPE)
>
>  /* Nonzero if TYPE represents a floating-point type, including complex
>     and vector floating-point types.  The vector and complex check does
>     not use the previous two macros to enable early folding.  */
>
>  #define FLOAT_TYPE_P(TYPE)                     \
>    (SCALAR_FLOAT_TYPE_P (TYPE)                  \
>     || ((TREE_CODE (TYPE) == COMPLEX_TYPE       \
> -        || TREE_CODE (TYPE) == VECTOR_TYPE)    \
> +        || VECTOR_TYPE_P (TYPE))               \
>         && SCALAR_FLOAT_TYPE_P (TREE_TYPE (TYPE))))
>
>  /* Nonzero if TYPE represents a decimal floating-point type.  */
>  #define DECIMAL_FLOAT_TYPE_P(TYPE)             \
>    (SCALAR_FLOAT_TYPE_P (TYPE)                  \
>     && DECIMAL_FLOAT_MODE_P (TYPE_MODE (TYPE)))
>
>  /* Nonzero if TYPE is a record or union type.  */
>  #define RECORD_OR_UNION_TYPE_P(TYPE)           \
>    (TREE_CODE (TYPE) == RECORD_TYPE             \
> @@ -2109,21 +2113,21 @@ struct GTY(()) tree_block {
>  #define TYPE_REFERENCE_TO(NODE) (TYPE_CHECK
> (NODE)->type_common.reference_to)
>  #define TYPE_PRECISION(NODE) (TYPE_CHECK (NODE)->type_common.precision)
>  #define TYPE_NAME(NODE) (TYPE_CHECK (NODE)->type_common.name)
>  #define TYPE_NEXT_VARIANT(NODE) (TYPE_CHECK
> (NODE)->type_common.next_variant)
>  #define TYPE_MAIN_VARIANT(NODE) (TYPE_CHECK
> (NODE)->type_common.main_variant)
>  #define TYPE_CONTEXT(NODE) (TYPE_CHECK (NODE)->type_common.context)
>
>  /* Vector types need to check target flags to determine type.  */
>  extern enum machine_mode vector_type_mode (const_tree);
>  #define TYPE_MODE(NODE) \
> -  (TREE_CODE (TYPE_CHECK (NODE)) == VECTOR_TYPE \
> +  (VECTOR_TYPE_P (TYPE_CHECK (NODE)) \
>     ? vector_type_mode (NODE) : (NODE)->type_common.mode)
>  #define SET_TYPE_MODE(NODE, MODE) \
>    (TYPE_CHECK (NODE)->type_common.mode = (MODE))
>
>  /* The "canonical" type for this type node, which is used by frontends to
>     compare the type for equality with another type.  If two types are
>     equal (based on the semantics of the language), then they will have
>     equivalent TYPE_CANONICAL entries.
>
>     As a special case, if TYPE_CANONICAL is NULL_TREE, and thus
> 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)
> @@ -4659,20 +4659,21 @@ fold_cond_expr_with_comparison (location
>
>       The conversions to max() and min() are not correct if B is
>       a number and A is not.  The conditions in the original
>       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
> +         || 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)))
>      {
>        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.  */
> @@ -13891,37 +13892,46 @@ fold_ternary_loc (location_t loc, enum t
>         {
>           unsigned HOST_WIDE_INT idx;
>           tree field, value;
>           FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (arg0), idx, field,
> value)
>             if (field == arg1)
>               return value;
>         }
>        return NULL_TREE;
>
>      case COND_EXPR:
> +    case VEC_COND_EXPR:
>        /* Pedantic ANSI C says that a conditional expression is never an
> lvalue,
>          so all simple results must be passed through pedantic_non_lvalue.
> */
>        if (TREE_CODE (arg0) == INTEGER_CST)
>         {
>           tree unused_op = integer_zerop (arg0) ? op1 : op2;
>           tem = integer_zerop (arg0) ? op2 : op1;
>           /* Only optimize constant conditions when the selected branch
>              has the same type as the COND_EXPR.  This avoids optimizing
>               away "c ? x : throw", where the throw has a void type.
>               Avoid throwing away that operand which contains label.  */
>            if ((!TREE_SIDE_EFFECTS (unused_op)
>                 || !contains_label_p (unused_op))
>                && (! VOID_TYPE_P (TREE_TYPE (tem))
>                    || VOID_TYPE_P (type)))
>             return pedantic_non_lvalue_loc (loc, tem);
>           return NULL_TREE;
>         }
> +      else if (TREE_CODE (arg0) == VECTOR_CST)
> +       {
> +         if (integer_all_onesp (arg0))
> +           return pedantic_omit_one_operand_loc (loc, type, arg1, arg2);
> +         if (integer_zerop (arg0))
> +           return pedantic_omit_one_operand_loc (loc, type, arg2, arg1);
> +       }
> +
>        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)
> @@ -13943,20 +13953,24 @@ fold_ternary_loc (location_t loc, enum t
>           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;
>             }
>         }
>
> +      /* ???  Fixup the code below for VEC_COND_EXPR.  */
> +      if (code == VEC_COND_EXPR)
> +       return NULL_TREE;
> +
>        /* If the second operand is simpler than the third, swap them
>          since that produces better jump optimization results.  */
>        if (truth_value_p (TREE_CODE (arg0))
>           && tree_swap_operands_p (op1, op2, false))
>         {
>           location_t loc0 = expr_location_or (arg0, loc);
>           /* See if this can be inverted.  If it can't, possibly because
>              it was a floating-point inequality comparison, don't do
>              anything.  */
>           tem = fold_truth_not_expr (loc0, arg0);
> @@ -14130,30 +14144,20 @@ fold_ternary_loc (location_t loc, enum t
>        /* Convert A ? 1 : B into A || B if A and B are truth values.  */
>        if (integer_onep (arg1)
>           && truth_value_p (TREE_CODE (arg0))
>           && truth_value_p (TREE_CODE (op2)))
>         return fold_build2_loc (loc, TRUTH_ORIF_EXPR, type,
>                             fold_convert_loc (loc, type, arg0),
>                             op2);
>
>        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);
> -       }
> -      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
>                && TREE_CODE (TREE_TYPE (arg0)) == VECTOR_TYPE))
>           && (type == TREE_TYPE (TREE_TYPE (arg0))
>

^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2013-03-19 15:15 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-03-17 15:47 Fold VEC_COND_EXPR to abs, min, max Marc Glisse
2013-03-18  9:30 ` Richard Biener
2013-03-18 10:27   ` Marc Glisse
2013-03-18 10:45     ` Richard Biener
2013-03-18 11:06       ` Marc Glisse
2013-03-18 11:11         ` Richard Biener
     [not found] ` <alpine.DEB.2.02.1303190848180.32548@stedding.saclay.inria.fr>
2013-03-19 15:15   ` Richard Biener

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).