[PATCH] D59174: [DAGCombine] Fold (x & ~y) | y patterns

Roman Lebedev via Phabricator via llvm-commits llvm-commits at lists.llvm.org
Sun Mar 17 05:40:54 PDT 2019


lebedev.ri accepted this revision.
lebedev.ri added a comment.
This revision is now accepted and ready to land.

Thanks, looks ok, other than repetition..



================
Comment at: llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp:5429
 
+  // fold (or (and X, (xor Y, -1)), Y) -> (or X, Y)
+  if (N0.getOpcode() == ISD::AND && isBitwiseNot(N0.getOperand(1)) &&
----------------
nikic wrote:
> lebedev.ri wrote:
> > There are 4 variations of this pattern, both `or` and `and` are commutative.
> Right you are. I've added these now, which resulted in a few more changes to the variablemask tests. I was under the mistaken impression that `(and X, (xor Y, -1))` is a canonicalized and-not pattern.
That is indeed a very subtle (and costly!) thing.
`(and X, (xor Y, -1))` will be in that order (well, some deterministic order).
But what if `X` and `Y` aren't arguments, but some values (instructions)?
Then they will also affect the weights and thus ordering.



================
Comment at: llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp:5429
 
+  // fold (or (and X, (xor Y, -1)), Y) -> (or X, Y)
+  if (N0.getOpcode() == ISD::AND && isBitwiseNot(N0.getOperand(1)) &&
----------------
lebedev.ri wrote:
> nikic wrote:
> > lebedev.ri wrote:
> > > There are 4 variations of this pattern, both `or` and `and` are commutative.
> > Right you are. I've added these now, which resulted in a few more changes to the variablemask tests. I was under the mistaken impression that `(and X, (xor Y, -1))` is a canonicalized and-not pattern.
> That is indeed a very subtle (and costly!) thing.
> `(and X, (xor Y, -1))` will be in that order (well, some deterministic order).
> But what if `X` and `Y` aren't arguments, but some values (instructions)?
> Then they will also affect the weights and thus ordering.
> 
Hmm, nobody likes that there is no pattern matching in back end :/
But this duplication isn't too nice too.
Can you try this instead:
```
// Fold all 4 commutative variations of    or (and (xor Y, -1), X), Y
// to                                      or X, Y
static SDValue foldDegradedBitselect(SDNode *N, SelectionDAG &DAG) {
  assert(N->getOpcode() == ISD::OR && "outermost node should be 'or'.");

  SDValue X, Y;
  auto outerMatcher = [N, &X, &Y](bool swap) {
    SDValue And = N->getOperand(0);
    Y = N->getOperand(1);

    if (And.getOpcode() != ISD::AND || swap)
      std::swap(And, Y);
    if (And.getOpcode() != ISD::AND)
      return false;

    auto innerMatcher = [And, Y, &X](bool swap) {
      assert(And.getOpcode() == ISD::AND);

      SDValue NotY = And.getOperand(0);
      X = And.getOperand(1);

      if (!isBitwiseNot(NotY) || swap)
        std::swap(NotY, X);
      if (!isBitwiseNot(NotY))
        return false;

      SDValue Y2 = NotY.getOperand(0);

      return Y == Y2;
    };

    return innerMatcher(/*swap=*/false) || innerMatcher(/*swap=*/true);
  };

  if (!(outerMatcher(/*swap=*/false) || outerMatcher(/*swap=*/true)))
    return SDValue();

  return DAG.getNode(ISD::OR, SDLoc(Y), Y.getValueType(), X, Y);
}
```
?

If that doesn't work, at least factor out these 4 duplicate if's into a function.


================
Comment at: llvm/test/CodeGen/AArch64/unfold-masked-merge-scalar-variablemask.ll:358
 }
 ; This is not a canonical form. Testing for completeness only.
 define i32 @out_constant_varx_mone_invmask(i32 %x, i32 %y, i32 %mask) {
----------------
(good thing i wrote all these then-pointless redundant tests i guess)


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D59174/new/

https://reviews.llvm.org/D59174





More information about the llvm-commits mailing list