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 <[email protected]>
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 GlisseIndex: 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;