Message ID | 20240813043023.3685386-3-quic_apinski@quicinc.com |
---|---|
State | New |
Headers | show |
Series | [1/3] testsuite: Add testcases for part of PR 103660 | expand |
On Tue, Aug 13, 2024 at 6:31 AM Andrew Pinski <quic_apinski@quicinc.com> wrote: > > This adds a pattern to convert `(a ? b : 0) | (a ? 0 : c)` into `a ? b : c` > which is simplier. It adds both for cond and vec_cond; even though vec_cond is > handled via a different pattern currently but requires extra steps for matching > so this should be slightly faster. > > Also handle it for xor and plus too since those can be handled the same way. > > Bootstrapped and tested on x86_64-linux-gnu with no regressions. OK. > PR tree-optimization/103660 > > gcc/ChangeLog: > > * match.pd (`(a ? b : 0) | (a ? 0 : c)`): New pattern. > > gcc/testsuite/ChangeLog: > > * g++.dg/tree-ssa/pr103660-4.C: New test. > * gcc.dg/tree-ssa/pr103660-4.c: New test. > > Signed-off-by: Andrew Pinski <quic_apinski@quicinc.com> > --- > gcc/match.pd | 10 +++++ > gcc/testsuite/g++.dg/tree-ssa/pr103660-4.C | 35 ++++++++++++++++++ > gcc/testsuite/gcc.dg/tree-ssa/pr103660-4.c | 43 ++++++++++++++++++++++ > 3 files changed, 88 insertions(+) > create mode 100644 gcc/testsuite/g++.dg/tree-ssa/pr103660-4.C > create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/pr103660-4.c > > diff --git a/gcc/match.pd b/gcc/match.pd > index b43ceb6def0..65a3aae2243 100644 > --- a/gcc/match.pd > +++ b/gcc/match.pd > @@ -2339,6 +2339,16 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT) > (if (INTEGRAL_TYPE_P (type)) > (bit_and @0 @1))) > > +/* Fold `(a ? b : 0) | (a ? 0 : c)` into (a ? b : c). > + Handle also ^ and + in replacement of `|`. */ > +(for cnd (cond vec_cond) > + (for op (bit_ior bit_xor plus) > + (simplify > + (op:c > + (cnd:s @0 @00 integer_zerop) > + (cnd:s @0 integer_zerop @01)) > + (cnd @0 @00 @01)))) > + > (for cmp (tcc_comparison) > icmp (inverted_tcc_comparison) > /* Fold (((a < b) & c) | ((a >= b) & d)) into (a < b ? c : d) & 1. */ > diff --git a/gcc/testsuite/g++.dg/tree-ssa/pr103660-4.C b/gcc/testsuite/g++.dg/tree-ssa/pr103660-4.C > new file mode 100644 > index 00000000000..47727f86e24 > --- /dev/null > +++ b/gcc/testsuite/g++.dg/tree-ssa/pr103660-4.C > @@ -0,0 +1,35 @@ > +/* PR tree-optimization/103660 */ > +/* Vector type version. */ > +/* { dg-do compile } */ > +/* { dg-options "-O1 -fdump-tree-forwprop2-raw -Wno-psabi" } */ > + > +typedef int v4si __attribute((__vector_size__(4 * sizeof(int)))); > +#define funcs(OP,n) \ > +v4si min_##n(v4si a, v4si b) { \ > + v4si t = {0,0,0,0}; \ > + v4si X = a < b ? a : t; \ > + v4si Y = a < b ? t : b; \ > + return (X OP Y); \ > +} \ > +v4si f_##n(v4si a, v4si b, \ > + v4si c, v4si d) { \ > + v4si t = {0,0,0,0}; \ > + v4si X = a < b ? c : t; \ > + v4si Y = a < b ? t : d; \ > + return (X OP Y); \ > +} > + > + > +funcs(|, ior) > +funcs(^, xor) > +funcs(+, plus) > + > +/* min_ior/min_xor/min_plus should produce min<a,b> or `a < b ? a : b` depending on if the target > + supports min on the vector type or not. */ > +/* f_ior/f_xor/f_plus should produce (a < b) ? c : d */ > +/* { dg-final { scan-tree-dump-not "bit_xor_expr, " "forwprop2" } } */ > +/* { dg-final { scan-tree-dump-not "bit_ior_expr, " "forwprop2" } } */ > +/* { dg-final { scan-tree-dump-not "plus_expr, " "forwprop2" } } */ > +/* { dg-final { scan-tree-dump-not "bit_ior_expr, " "forwprop2" } } */ > +/* { dg-final { scan-tree-dump-times "(?:lt_expr|min_expr), " 6 "forwprop2" } } */ > +/* { dg-final { scan-tree-dump-times "(?:vec_cond_expr|min_expr), " 6 "forwprop2" } } */ > diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr103660-4.c b/gcc/testsuite/gcc.dg/tree-ssa/pr103660-4.c > new file mode 100644 > index 00000000000..26c956fdcec > --- /dev/null > +++ b/gcc/testsuite/gcc.dg/tree-ssa/pr103660-4.c > @@ -0,0 +1,43 @@ > +/* PR tree-optimization/103660 */ > +/* { dg-do compile } */ > +/* { dg-options "-O1 -fgimple -fdump-tree-forwprop1-raw" } */ > + > +#define funcs(OP,n) \ > +__GIMPLE() \ > +int min_##n(int a, int b) { \ > + _Bool X; \ > + int t; \ > + int t1; \ > + int t2; \ > + X = a < b; \ > + t1 = X ? a : 0; \ > + t2 = X ? 0 : b; \ > + t = t1 OP t2; \ > + return t; \ > +} \ > +__GIMPLE() \ > +int f_##n(int a, int b, int c, \ > + int d) { \ > + _Bool X; \ > + int t; \ > + int t1; \ > + int t2; \ > + X = a < b; \ > + t1 = X ? c : 0; \ > + t2 = X ? 0 : d; \ > + t = t1 OP t2; \ > + return t; \ > +} > + > +funcs(|, ior) > +funcs(^, xor) > +funcs(+, plus) > + > +/* min_i/min_ioror/min_plus should produce min<a,b> */ > +/* f_xor/f_ior/f_plus should produce (a < b) ? c : d */ > +/* { dg-final { scan-tree-dump-not "bit_xor_expr, " "forwprop1" } } */ > +/* { dg-final { scan-tree-dump-not "bit_ior_expr, " "forwprop1" } } */ > +/* { dg-final { scan-tree-dump-not "plus_expr, " "forwprop1" } } */ > +/* { dg-final { scan-tree-dump-times "min_expr, " 3 "forwprop1" } } */ > +/* { dg-final { scan-tree-dump-times "lt_expr, " 3 "forwprop1" } } */ > +/* { dg-final { scan-tree-dump-times "cond_expr, " 3 "forwprop1" } } */ > -- > 2.43.0 >
>> --- a/gcc/match.pd >> +++ b/gcc/match.pd >> @@ -2339,6 +2339,16 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT) >> (if (INTEGRAL_TYPE_P (type)) >> (bit_and @0 @1))) >> >> +/* Fold `(a ? b : 0) | (a ? 0 : c)` into (a ? b : c). >> + Handle also ^ and + in replacement of `|`. */ >> +(for cnd (cond vec_cond) >> + (for op (bit_ior bit_xor plus) >> + (simplify >> + (op:c >> + (cnd:s @0 @00 integer_zerop) >> + (cnd:s @0 integer_zerop @01)) >> + (cnd @0 @00 @01)))) Wouldn't it fall into something more generic like (for cnd (cond vec_cond) (for op (any_binary) (simplify (op (cnd:s @0 @1 @2) (cnd:s @0 @3 @4)) (cnd @0 (op! @1 @3) (op! @2 @4))))) ? The example given in the doc for the use of '!' is pretty close @smallexample (simplify (plus (vec_cond:s @@0 @@1 @@2) @@3) (vec_cond @@0 (plus! @@1 @@3) (plus! @@2 @@3))) @end smallexample
> -----Original Message----- > From: Marc Glisse <marc.glisse@inria.fr> > Sent: Monday, August 26, 2024 4:46 AM > To: Richard Biener <richard.guenther@gmail.com> > Cc: Andrew Pinski (QUIC) <quic_apinski@quicinc.com>; gcc- > patches@gcc.gnu.org > Subject: Re: [PATCH 3/3] Match: Add pattern for `(a ? b : 0) | (a > ? 0 : c)` into `a ? b : c` [PR103660] > > >> --- a/gcc/match.pd > >> +++ b/gcc/match.pd > >> @@ -2339,6 +2339,16 @@ > DEFINE_INT_AND_FLOAT_ROUND_FN (RINT) > >> (if (INTEGRAL_TYPE_P (type)) > >> (bit_and @0 @1))) > >> > >> +/* Fold `(a ? b : 0) | (a ? 0 : c)` into (a ? b : c). > >> + Handle also ^ and + in replacement of `|`. */ (for cnd > (cond > >> +vec_cond) (for op (bit_ior bit_xor plus) > >> + (simplify > >> + (op:c > >> + (cnd:s @0 @00 integer_zerop) > >> + (cnd:s @0 integer_zerop @01)) > >> + (cnd @0 @00 @01)))) > > Wouldn't it fall into something more generic like > > (for cnd (cond vec_cond) > (for op (any_binary) > (simplify > (op > (cnd:s @0 @1 @2) > (cnd:s @0 @3 @4)) > (cnd @0 (op! @1 @3) (op! @2 @4))))) > > ? > > The example given in the doc for the use of '!' is pretty close Yes we can extend the pattern that is already there for vec_cond too. Though I also think we keep the special case for the newly added because then we need to extra steps to see that op is no longer there. Another thing longer term is to remove VEC_COND_EXPR and merge it with COND_EXPP. I know this was already mentioned in a different thread but I don't want to duplicate work someone else might be doing; so, I have held back on trying to implement that. Thanks, Andrew Pinski > > @smallexample > (simplify > (plus (vec_cond:s @@0 @@1 @@2) @@3) > (vec_cond @@0 (plus! @@1 @@3) (plus! @@2 @@3))) > @end smallexample > > -- > Marc Glisse
diff --git a/gcc/match.pd b/gcc/match.pd index b43ceb6def0..65a3aae2243 100644 --- a/gcc/match.pd +++ b/gcc/match.pd @@ -2339,6 +2339,16 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT) (if (INTEGRAL_TYPE_P (type)) (bit_and @0 @1))) +/* Fold `(a ? b : 0) | (a ? 0 : c)` into (a ? b : c). + Handle also ^ and + in replacement of `|`. */ +(for cnd (cond vec_cond) + (for op (bit_ior bit_xor plus) + (simplify + (op:c + (cnd:s @0 @00 integer_zerop) + (cnd:s @0 integer_zerop @01)) + (cnd @0 @00 @01)))) + (for cmp (tcc_comparison) icmp (inverted_tcc_comparison) /* Fold (((a < b) & c) | ((a >= b) & d)) into (a < b ? c : d) & 1. */ diff --git a/gcc/testsuite/g++.dg/tree-ssa/pr103660-4.C b/gcc/testsuite/g++.dg/tree-ssa/pr103660-4.C new file mode 100644 index 00000000000..47727f86e24 --- /dev/null +++ b/gcc/testsuite/g++.dg/tree-ssa/pr103660-4.C @@ -0,0 +1,35 @@ +/* PR tree-optimization/103660 */ +/* Vector type version. */ +/* { dg-do compile } */ +/* { dg-options "-O1 -fdump-tree-forwprop2-raw -Wno-psabi" } */ + +typedef int v4si __attribute((__vector_size__(4 * sizeof(int)))); +#define funcs(OP,n) \ +v4si min_##n(v4si a, v4si b) { \ + v4si t = {0,0,0,0}; \ + v4si X = a < b ? a : t; \ + v4si Y = a < b ? t : b; \ + return (X OP Y); \ +} \ +v4si f_##n(v4si a, v4si b, \ + v4si c, v4si d) { \ + v4si t = {0,0,0,0}; \ + v4si X = a < b ? c : t; \ + v4si Y = a < b ? t : d; \ + return (X OP Y); \ +} + + +funcs(|, ior) +funcs(^, xor) +funcs(+, plus) + +/* min_ior/min_xor/min_plus should produce min<a,b> or `a < b ? a : b` depending on if the target + supports min on the vector type or not. */ +/* f_ior/f_xor/f_plus should produce (a < b) ? c : d */ +/* { dg-final { scan-tree-dump-not "bit_xor_expr, " "forwprop2" } } */ +/* { dg-final { scan-tree-dump-not "bit_ior_expr, " "forwprop2" } } */ +/* { dg-final { scan-tree-dump-not "plus_expr, " "forwprop2" } } */ +/* { dg-final { scan-tree-dump-not "bit_ior_expr, " "forwprop2" } } */ +/* { dg-final { scan-tree-dump-times "(?:lt_expr|min_expr), " 6 "forwprop2" } } */ +/* { dg-final { scan-tree-dump-times "(?:vec_cond_expr|min_expr), " 6 "forwprop2" } } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr103660-4.c b/gcc/testsuite/gcc.dg/tree-ssa/pr103660-4.c new file mode 100644 index 00000000000..26c956fdcec --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/pr103660-4.c @@ -0,0 +1,43 @@ +/* PR tree-optimization/103660 */ +/* { dg-do compile } */ +/* { dg-options "-O1 -fgimple -fdump-tree-forwprop1-raw" } */ + +#define funcs(OP,n) \ +__GIMPLE() \ +int min_##n(int a, int b) { \ + _Bool X; \ + int t; \ + int t1; \ + int t2; \ + X = a < b; \ + t1 = X ? a : 0; \ + t2 = X ? 0 : b; \ + t = t1 OP t2; \ + return t; \ +} \ +__GIMPLE() \ +int f_##n(int a, int b, int c, \ + int d) { \ + _Bool X; \ + int t; \ + int t1; \ + int t2; \ + X = a < b; \ + t1 = X ? c : 0; \ + t2 = X ? 0 : d; \ + t = t1 OP t2; \ + return t; \ +} + +funcs(|, ior) +funcs(^, xor) +funcs(+, plus) + +/* min_i/min_ioror/min_plus should produce min<a,b> */ +/* f_xor/f_ior/f_plus should produce (a < b) ? c : d */ +/* { dg-final { scan-tree-dump-not "bit_xor_expr, " "forwprop1" } } */ +/* { dg-final { scan-tree-dump-not "bit_ior_expr, " "forwprop1" } } */ +/* { dg-final { scan-tree-dump-not "plus_expr, " "forwprop1" } } */ +/* { dg-final { scan-tree-dump-times "min_expr, " 3 "forwprop1" } } */ +/* { dg-final { scan-tree-dump-times "lt_expr, " 3 "forwprop1" } } */ +/* { dg-final { scan-tree-dump-times "cond_expr, " 3 "forwprop1" } } */
This adds a pattern to convert `(a ? b : 0) | (a ? 0 : c)` into `a ? b : c` which is simplier. It adds both for cond and vec_cond; even though vec_cond is handled via a different pattern currently but requires extra steps for matching so this should be slightly faster. Also handle it for xor and plus too since those can be handled the same way. Bootstrapped and tested on x86_64-linux-gnu with no regressions. PR tree-optimization/103660 gcc/ChangeLog: * match.pd (`(a ? b : 0) | (a ? 0 : c)`): New pattern. gcc/testsuite/ChangeLog: * g++.dg/tree-ssa/pr103660-4.C: New test. * gcc.dg/tree-ssa/pr103660-4.c: New test. Signed-off-by: Andrew Pinski <quic_apinski@quicinc.com> --- gcc/match.pd | 10 +++++ gcc/testsuite/g++.dg/tree-ssa/pr103660-4.C | 35 ++++++++++++++++++ gcc/testsuite/gcc.dg/tree-ssa/pr103660-4.c | 43 ++++++++++++++++++++++ 3 files changed, 88 insertions(+) create mode 100644 gcc/testsuite/g++.dg/tree-ssa/pr103660-4.C create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/pr103660-4.c