On Sun, Mar 17, 2013 at 4:46 PM, Marc Glisse <marc.gli...@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.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))
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; >