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(-)

Reply via email to