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;