This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Fold VEC_COND_EXPR to abs, min, max


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

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]