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.gli...@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))
     {
       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;

Reply via email to