On 04/05/2022 12:14, Richard Biener wrote:
On Wed, May 4, 2022 at 12:16 PM Richard Earnshaw via Gcc-patches
<gcc-patches@gcc.gnu.org> wrote:
Gimple isel already handles x CMP y ? -1 : 0 when lowering vector cond
operations, but this can be generalized further when the comparison
forms a natural mask so that we can also handle x CMP y ? z : 0 by
transforming it into (x CMP y) & z. This will, in most cases save
having to load a register with the zero vector.
Hmm, I'm not sure why exactly the existing case is in ISEL but if
we want to extend it there we migh also want to handle ? 0 : -1
as BIT_NOT.
I was assuming that there had already been some level of
canonicalization at this point, but maybe that's an incorrect
assumption. There are quite a few transforms that would avoid a select
operation, but at some point the bit manipulations may well become more
expensive than the select itself.
For the case in question it looks like it might better fit as optimization
in match.pd? It also lacks a query for present and<mode>3 support.
For match.pd it might be nice to handle x CMP y ? 0 : z as well
if we can invert x CMP y (and it has only a single use). When in
ISEL we might as well check for andn<mode>3 support and go with
BIT_NOT + BIT_AND ...
I'll have to think about that a bit, the approach was inspired by the
hunk just a bit earlier that starts:
/* Lower mask typed, non-vector mode VEC_COND_EXPRs to bitwise
operations.
Those can end up generated by folding and at least for integer
mode masks
we cannot expect vcond expanders to exist. We lower a ? b : c
to (b & a) | (c & ~a). */
if (VECTOR_BOOLEAN_TYPE_P (TREE_TYPE (lhs))
&& !VECTOR_MODE_P (mode))
{
gcc_assert (types_compatible_p (TREE_TYPE (op0), TREE_TYPE (op1)));
gimple_seq stmts = NULL;
tree type = TREE_TYPE (lhs);
location_t loc = gimple_location (stmt);
tree tem0 = gimple_build (&stmts, loc, BIT_AND_EXPR, type, op1, op0);
There's no test for and<mode>3 support there, but I guess that's working
on integral modes rather than vectors.
Do you have a testcase where it improves code generation btw?
It was originally inspired by:
void f (int * __restrict__ dest, int *a, int *b)
{
int i;
for (i=0; i<4; i++) {
dest[i] = a[i] == b[i];
}
}
which with Neon on Arm was producing a vsel sequence rather than a mask
operation because the backend doesn't handle this case directly during
expand (unlike some other targets); but it seemed wrong for every target
to have to handle this in the back-end when it's a pretty generic
optimization.
A more generalized case would be something like
void f (int * __restrict__ dest, int *a, int *b)
{
int i;
for (i=0; i<4; i++) {
dest[i] = a[i] ? b[i] : 0;
}
}
R.
Richard.
gcc/ChangeLog:
* gimple-isel.cc (gimple_expand_vec_cond_expr): Handle
x CMP y ? z : 0.
---
gcc/gimple-isel.cc | 29 +++++++++++++++++++++++------
1 file changed, 23 insertions(+), 6 deletions(-)