Message ID | alpine.DEB.2.02.1303171624310.8443@stedding.saclay.inria.fr |
---|---|
State | New |
Headers | show |
On Sun, Mar 17, 2013 at 4:46 PM, Marc Glisse <marc.glisse@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.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)) 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; >
On Mon, 18 Mar 2013, Richard Biener wrote: >> 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. >> @@ -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? Yes, as I mention in the ChangeLog. Not just the C++ front-end, it never makes sense to use a VEC_COND_EXPR as an lvalue, it really is just a ternary variant of BIT_AND_EXPR. > 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; Makes sense, I'll rework the patch. Thanks,
On Mon, Mar 18, 2013 at 11:27 AM, Marc Glisse <marc.glisse@inria.fr> wrote: > On Mon, 18 Mar 2013, Richard Biener wrote: > >>> 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. > > >>> @@ -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? > > > Yes, as I mention in the ChangeLog. Not just the C++ front-end, it never > makes sense to use a VEC_COND_EXPR as an lvalue, it really is just a ternary > variant of BIT_AND_EXPR. Then please add a && TREE_CODE == COND_EXPR around the code handling only COND_EXPRs instead. Richard. > >> 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; > > > Makes sense, I'll rework the patch. > > Thanks, > > -- > Marc Glisse
On Mon, 18 Mar 2013, Richard Biener wrote: > On Mon, Mar 18, 2013 at 11:27 AM, Marc Glisse <marc.glisse@inria.fr> wrote: >> On Mon, 18 Mar 2013, Richard Biener wrote: >>> You mean that the VEC_COND_EXPRs can never be used as an lvalue in >>> the C++ frontend? >> >> Yes, as I mention in the ChangeLog. Not just the C++ front-end, it never >> makes sense to use a VEC_COND_EXPR as an lvalue, it really is just a ternary >> variant of BIT_AND_EXPR. > > Then please add a && TREE_CODE == COND_EXPR around the > code handling only COND_EXPRs instead. Hmm, there isn't one. There is just a block of code that is disabled when the compiler is not certain that the result is not an lvalue. And the arguments it can use to prove that are: * we are in gimple form * we are not doing C++ * one of the alternatives is not an lvalue * (new) it is a vec_cond_expr Apart from changing TREE_CODE == VEC_COND_EXPR to TREE_CODE != COND_EXPR, I am not sure what to change. (Looking at the patch, I may have forgotten to check for side effects somewhere, the tests needed are not exactly the same as for COND_EXPR since VEC_COND_EXPR is not lazy, I'll check that before resubmitting)
On Mon, Mar 18, 2013 at 12:06 PM, Marc Glisse <marc.glisse@inria.fr> wrote: > On Mon, 18 Mar 2013, Richard Biener wrote: > >> On Mon, Mar 18, 2013 at 11:27 AM, Marc Glisse <marc.glisse@inria.fr> >> wrote: >>> >>> On Mon, 18 Mar 2013, Richard Biener wrote: >>>> >>>> You mean that the VEC_COND_EXPRs can never be used as an lvalue in >>>> the C++ frontend? >>> >>> >>> Yes, as I mention in the ChangeLog. Not just the C++ front-end, it never >>> makes sense to use a VEC_COND_EXPR as an lvalue, it really is just a >>> ternary >>> variant of BIT_AND_EXPR. >> >> >> Then please add a && TREE_CODE == COND_EXPR around the >> code handling only COND_EXPRs instead. > > > Hmm, there isn't one. There is just a block of code that is disabled when > the compiler is not certain that the result is not an lvalue. And the > arguments it can use to prove that are: > * we are in gimple form > * we are not doing C++ > * one of the alternatives is not an lvalue > * (new) it is a vec_cond_expr > > Apart from changing TREE_CODE == VEC_COND_EXPR to TREE_CODE != COND_EXPR, I > am not sure what to change. > > (Looking at the patch, I may have forgotten to check for side effects > somewhere, the tests needed are not exactly the same as for COND_EXPR since > VEC_COND_EXPR is not lazy, I'll check that before resubmitting) Hmm, I see we don't even have the code available in fold_cond_expr_with_comparison. So use 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 || VECTOR_TYPE_P (type) || (strcmp (lang_hooks.name, "GNU C++") != 0 && strcmp (lang_hooks.name, "GNU Objective-C++") != 0) || ! maybe_lvalue_p (arg1) || ! maybe_lvalue_p (arg2))) err - there isn't a VECTOR_TYPE_P predicate - time to add one ;) Thanks, Richard. > -- > 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;