* Fold VEC_COND_EXPR to abs, min, max
@ 2013-03-17 15:47 Marc Glisse
2013-03-18 9:30 ` Richard Biener
[not found] ` <alpine.DEB.2.02.1303190848180.32548@stedding.saclay.inria.fr>
0 siblings, 2 replies; 7+ messages in thread
From: Marc Glisse @ 2013-03-17 15:47 UTC (permalink / raw)
To: gcc-patches
[-- Attachment #1: Type: TEXT/PLAIN, Size: 882 bytes --]
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
[-- Attachment #2: Type: TEXT/PLAIN, Size: 6414 bytes --]
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;
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: Fold VEC_COND_EXPR to abs, min, max
2013-03-17 15:47 Fold VEC_COND_EXPR to abs, min, max Marc Glisse
@ 2013-03-18 9:30 ` Richard Biener
2013-03-18 10:27 ` Marc Glisse
[not found] ` <alpine.DEB.2.02.1303190848180.32548@stedding.saclay.inria.fr>
1 sibling, 1 reply; 7+ messages in thread
From: Richard Biener @ 2013-03-18 9:30 UTC (permalink / raw)
To: Marc Glisse; +Cc: gcc-patches
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;
>
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: Fold VEC_COND_EXPR to abs, min, max
2013-03-18 9:30 ` Richard Biener
@ 2013-03-18 10:27 ` Marc Glisse
2013-03-18 10:45 ` Richard Biener
0 siblings, 1 reply; 7+ messages in thread
From: Marc Glisse @ 2013-03-18 10:27 UTC (permalink / raw)
To: Richard Biener; +Cc: gcc-patches
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,
--
Marc Glisse
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: Fold VEC_COND_EXPR to abs, min, max
2013-03-18 10:27 ` Marc Glisse
@ 2013-03-18 10:45 ` Richard Biener
2013-03-18 11:06 ` Marc Glisse
0 siblings, 1 reply; 7+ messages in thread
From: Richard Biener @ 2013-03-18 10:45 UTC (permalink / raw)
To: Marc Glisse; +Cc: gcc-patches
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
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: Fold VEC_COND_EXPR to abs, min, max
2013-03-18 10:45 ` Richard Biener
@ 2013-03-18 11:06 ` Marc Glisse
2013-03-18 11:11 ` Richard Biener
0 siblings, 1 reply; 7+ messages in thread
From: Marc Glisse @ 2013-03-18 11:06 UTC (permalink / raw)
To: Richard Biener; +Cc: gcc-patches
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)
--
Marc Glisse
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: Fold VEC_COND_EXPR to abs, min, max
2013-03-18 11:06 ` Marc Glisse
@ 2013-03-18 11:11 ` Richard Biener
0 siblings, 0 replies; 7+ messages in thread
From: Richard Biener @ 2013-03-18 11:11 UTC (permalink / raw)
To: Marc Glisse; +Cc: gcc-patches
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
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: Fold VEC_COND_EXPR to abs, min, max
[not found] ` <alpine.DEB.2.02.1303190848180.32548@stedding.saclay.inria.fr>
@ 2013-03-19 15:15 ` Richard Biener
0 siblings, 0 replies; 7+ messages in thread
From: Richard Biener @ 2013-03-19 15:15 UTC (permalink / raw)
To: Marc Glisse; +Cc: gcc-patches
On Tue, Mar 19, 2013 at 9:06 AM, Marc Glisse <marc.glisse@inria.fr> wrote:
> Hello,
>
> new version of the patch. Note that for the simplification from {-1,-1}?a:b
> to a, I removed the test that b has no side effects and call
> pedantic_omit_one_operand_loc instead.
>
>
> Bootstrap + testsuite on x86_64-linux-gnu.
Ok.
Thanks,
Richard.
> 2013-03-19 Marc Glisse <marc.glisse@inria.fr>
>
> gcc/
> * tree.h (VECTOR_TYPE_P): New macro.
> (VECTOR_INTEGER_TYPE_P, VECTOR_FLOAT_TYPE_P, FLOAT_TYPE_P,
> TYPE_MODE): Use it.
>
> * fold-const.c (fold_cond_expr_with_comparison): Use build_zero_cst.
> VEC_COND_EXPR cannot be lvalues.
> (fold_ternary_loc) <VEC_COND_EXPR>: Merge with the COND_EXPR case.
>
>
> 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:eol-style
> + native
> Added: svn:keywords
> + Author Date Id Revision URL
>
> 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: gcc/tree.h
> ===================================================================
> --- gcc/tree.h (revision 196748)
> +++ gcc/tree.h (working copy)
> @@ -974,20 +974,24 @@ extern void omp_clause_range_check_faile
> && (TREE_TYPE (EXP) \
> == TREE_TYPE (TREE_OPERAND (EXP, 0)))) \
> (EXP) = TREE_OPERAND (EXP, 0)
>
> /* Remove unnecessary type conversions according to
> tree_ssa_useless_type_conversion. */
>
> #define STRIP_USELESS_TYPE_CONVERSION(EXP) \
> (EXP) = tree_ssa_strip_useless_type_conversions (EXP)
>
> +/* Nonzero if TYPE represents a vector type. */
> +
> +#define VECTOR_TYPE_P(TYPE) (TREE_CODE (TYPE) == VECTOR_TYPE)
> +
> /* Nonzero if TYPE represents an integral type. Note that we do not
> include COMPLEX types here. Keep these checks in ascending code
> order. */
>
> #define INTEGRAL_TYPE_P(TYPE) \
> (TREE_CODE (TYPE) == ENUMERAL_TYPE \
> || TREE_CODE (TYPE) == BOOLEAN_TYPE \
> || TREE_CODE (TYPE) == INTEGER_TYPE)
>
> /* Nonzero if TYPE represents a non-saturating fixed-point type. */
> @@ -1009,39 +1013,39 @@ extern void omp_clause_range_check_faile
> #define SCALAR_FLOAT_TYPE_P(TYPE) (TREE_CODE (TYPE) == REAL_TYPE)
>
> /* Nonzero if TYPE represents a complex floating-point type. */
>
> #define COMPLEX_FLOAT_TYPE_P(TYPE) \
> (TREE_CODE (TYPE) == COMPLEX_TYPE \
> && TREE_CODE (TREE_TYPE (TYPE)) == REAL_TYPE)
>
> /* Nonzero if TYPE represents a vector integer type. */
>
> -#define VECTOR_INTEGER_TYPE_P(TYPE) \
> - (TREE_CODE (TYPE) == VECTOR_TYPE \
> - && TREE_CODE (TREE_TYPE (TYPE)) == INTEGER_TYPE)
> +#define VECTOR_INTEGER_TYPE_P(TYPE) \
> + (VECTOR_TYPE_P (TYPE) \
> + && TREE_CODE (TREE_TYPE (TYPE)) == INTEGER_TYPE)
>
>
> /* Nonzero if TYPE represents a vector floating-point type. */
>
> #define VECTOR_FLOAT_TYPE_P(TYPE) \
> - (TREE_CODE (TYPE) == VECTOR_TYPE \
> + (VECTOR_TYPE_P (TYPE) \
> && TREE_CODE (TREE_TYPE (TYPE)) == REAL_TYPE)
>
> /* Nonzero if TYPE represents a floating-point type, including complex
> and vector floating-point types. The vector and complex check does
> not use the previous two macros to enable early folding. */
>
> #define FLOAT_TYPE_P(TYPE) \
> (SCALAR_FLOAT_TYPE_P (TYPE) \
> || ((TREE_CODE (TYPE) == COMPLEX_TYPE \
> - || TREE_CODE (TYPE) == VECTOR_TYPE) \
> + || VECTOR_TYPE_P (TYPE)) \
> && SCALAR_FLOAT_TYPE_P (TREE_TYPE (TYPE))))
>
> /* Nonzero if TYPE represents a decimal floating-point type. */
> #define DECIMAL_FLOAT_TYPE_P(TYPE) \
> (SCALAR_FLOAT_TYPE_P (TYPE) \
> && DECIMAL_FLOAT_MODE_P (TYPE_MODE (TYPE)))
>
> /* Nonzero if TYPE is a record or union type. */
> #define RECORD_OR_UNION_TYPE_P(TYPE) \
> (TREE_CODE (TYPE) == RECORD_TYPE \
> @@ -2109,21 +2113,21 @@ struct GTY(()) tree_block {
> #define TYPE_REFERENCE_TO(NODE) (TYPE_CHECK
> (NODE)->type_common.reference_to)
> #define TYPE_PRECISION(NODE) (TYPE_CHECK (NODE)->type_common.precision)
> #define TYPE_NAME(NODE) (TYPE_CHECK (NODE)->type_common.name)
> #define TYPE_NEXT_VARIANT(NODE) (TYPE_CHECK
> (NODE)->type_common.next_variant)
> #define TYPE_MAIN_VARIANT(NODE) (TYPE_CHECK
> (NODE)->type_common.main_variant)
> #define TYPE_CONTEXT(NODE) (TYPE_CHECK (NODE)->type_common.context)
>
> /* Vector types need to check target flags to determine type. */
> extern enum machine_mode vector_type_mode (const_tree);
> #define TYPE_MODE(NODE) \
> - (TREE_CODE (TYPE_CHECK (NODE)) == VECTOR_TYPE \
> + (VECTOR_TYPE_P (TYPE_CHECK (NODE)) \
> ? vector_type_mode (NODE) : (NODE)->type_common.mode)
> #define SET_TYPE_MODE(NODE, MODE) \
> (TYPE_CHECK (NODE)->type_common.mode = (MODE))
>
> /* The "canonical" type for this type node, which is used by frontends to
> compare the type for equality with another type. If two types are
> equal (based on the semantics of the language), then they will have
> equivalent TYPE_CANONICAL entries.
>
> As a special case, if TYPE_CANONICAL is NULL_TREE, and thus
> 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)
> @@ -4659,20 +4659,21 @@ fold_cond_expr_with_comparison (location
>
> The conversions to max() and min() are not correct if B is
> a number and A is not. The conditions in the original
> 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
> + || 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)))
> {
> 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. */
> @@ -13891,37 +13892,46 @@ fold_ternary_loc (location_t loc, enum t
> {
> unsigned HOST_WIDE_INT idx;
> tree field, value;
> FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (arg0), idx, field,
> value)
> if (field == arg1)
> return value;
> }
> return NULL_TREE;
>
> case COND_EXPR:
> + case VEC_COND_EXPR:
> /* Pedantic ANSI C says that a conditional expression is never an
> lvalue,
> so all simple results must be passed through pedantic_non_lvalue.
> */
> if (TREE_CODE (arg0) == INTEGER_CST)
> {
> tree unused_op = integer_zerop (arg0) ? op1 : op2;
> tem = integer_zerop (arg0) ? op2 : op1;
> /* Only optimize constant conditions when the selected branch
> has the same type as the COND_EXPR. This avoids optimizing
> away "c ? x : throw", where the throw has a void type.
> Avoid throwing away that operand which contains label. */
> if ((!TREE_SIDE_EFFECTS (unused_op)
> || !contains_label_p (unused_op))
> && (! VOID_TYPE_P (TREE_TYPE (tem))
> || VOID_TYPE_P (type)))
> return pedantic_non_lvalue_loc (loc, tem);
> return NULL_TREE;
> }
> + else if (TREE_CODE (arg0) == VECTOR_CST)
> + {
> + if (integer_all_onesp (arg0))
> + return pedantic_omit_one_operand_loc (loc, type, arg1, arg2);
> + if (integer_zerop (arg0))
> + return pedantic_omit_one_operand_loc (loc, type, arg2, arg1);
> + }
> +
> 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)
> @@ -13943,20 +13953,24 @@ fold_ternary_loc (location_t loc, enum t
> 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;
> }
> }
>
> + /* ??? Fixup the code below for VEC_COND_EXPR. */
> + if (code == VEC_COND_EXPR)
> + return NULL_TREE;
> +
> /* If the second operand is simpler than the third, swap them
> since that produces better jump optimization results. */
> if (truth_value_p (TREE_CODE (arg0))
> && tree_swap_operands_p (op1, op2, false))
> {
> location_t loc0 = expr_location_or (arg0, loc);
> /* See if this can be inverted. If it can't, possibly because
> it was a floating-point inequality comparison, don't do
> anything. */
> tem = fold_truth_not_expr (loc0, arg0);
> @@ -14130,30 +14144,20 @@ fold_ternary_loc (location_t loc, enum t
> /* Convert A ? 1 : B into A || B if A and B are truth values. */
> if (integer_onep (arg1)
> && truth_value_p (TREE_CODE (arg0))
> && truth_value_p (TREE_CODE (op2)))
> return fold_build2_loc (loc, TRUTH_ORIF_EXPR, type,
> fold_convert_loc (loc, type, arg0),
> op2);
>
> 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);
> - }
> - 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
> && TREE_CODE (TREE_TYPE (arg0)) == VECTOR_TYPE))
> && (type == TREE_TYPE (TREE_TYPE (arg0))
>
^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2013-03-19 15:15 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-03-17 15:47 Fold VEC_COND_EXPR to abs, min, max Marc Glisse
2013-03-18 9:30 ` Richard Biener
2013-03-18 10:27 ` Marc Glisse
2013-03-18 10:45 ` Richard Biener
2013-03-18 11:06 ` Marc Glisse
2013-03-18 11:11 ` Richard Biener
[not found] ` <alpine.DEB.2.02.1303190848180.32548@stedding.saclay.inria.fr>
2013-03-19 15:15 ` Richard Biener
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).